lightprepass is functional again. still diffuse lighting only. supports shadowmaps but no other weird light info.

added 'pkg' console command. will still need more tweaking.
r_renderscale < 0 means nearest filtering (may need a vid_restart for that to take effect though).
fteqccgui: added 'make installer' options.
fteqcc: fix framemacro issue that was breaking due to invalid dupes in hipnotic's code
cl_lerp_smooth: by default now enabled for singleplayer as well as just demos. this smooths out platforms etc.
q2 demos: explicitly recognise .dm2 extension, to try to avoid issues.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5024 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2016-11-20 20:52:41 +00:00
parent f7d7a1a9fb
commit 8d09710ed1
48 changed files with 3043 additions and 936 deletions

View File

@ -548,6 +548,7 @@ void Cam_Unlock(playerview_t *pv)
CL_SendClientCommand(true, "ptrack");
pv->cam_state = CAM_FREECAM;
pv->viewentity = (cls.demoplayback)?0:(pv->playernum+1); //free floating
SCR_CenterPrint(pv-cl.playerview, NULL, true);
Sbar_Changed();
Skin_FlushPlayers();
@ -565,6 +566,7 @@ void Cam_Lock(playerview_t *pv, int playernum)
pv->cam_spec_track = playernum;
pv->cam_state = CAM_PENDING;
pv->viewentity = (cls.demoplayback)?0:(pv->playernum+1); //free floating until actually locked
SCR_CenterPrint(pv-cl.playerview, NULL, true);
Skin_FlushPlayers();

View File

@ -2208,25 +2208,28 @@ void CL_PlayDemoFile(vfsfile_t *f, char *demoname, qboolean issyspath)
}
#ifdef Q2CLIENT
//just assume if it has a known extension
if (!Q_strcasecmp(demoname + strlen(demoname) - 3, "dm2") ||
!Q_strcasecmp(demoname + strlen(demoname) - 6, "dm2.gz"))
{
int len;
char type;
int protocol;
//check if its a quake2 demo.
VFS_READ(f, &len, sizeof(len));
VFS_READ(f, &type, sizeof(type));
VFS_READ(f, &protocol, sizeof(protocol));
VFS_SEEK(f, start);
len = LittleLong(len);
protocol = LittleLong(protocol);
if (len > 5 && type == svcq2_serverdata && protocol != 0)
{
CL_PlayDemoStream(f, NULL, demoname, issyspath, DPB_QUAKE2, 0);
return;
}
VFS_SEEK(f, start);
CL_PlayDemoStream(f, NULL, demoname, issyspath, DPB_QUAKE2, 0);
return;
}
#endif
if (!Q_strcasecmp(demoname + strlen(demoname) - 3, "mvd") ||
!Q_strcasecmp(demoname + strlen(demoname) - 6, "mvd.gz"))
{
CL_PlayDemoStream(f, NULL, demoname, issyspath, DPB_MVD, 0);
return;
}
if (!Q_strcasecmp(demoname + strlen(demoname) - 3, "qwd") ||
!Q_strcasecmp(demoname + strlen(demoname) - 6, "qwd.gz"))
{
CL_PlayDemoStream(f, NULL, demoname, issyspath, DPB_QUAKEWORLD, 0);
return;
}
#ifdef NQPROT
{
@ -2256,15 +2259,57 @@ void CL_PlayDemoFile(vfsfile_t *f, char *demoname, qboolean issyspath)
}
#endif
//its not NQ then. must be QuakeWorld, either .qwd or .mvd
#ifdef Q2CLIENT
{
int len;
char type;
int protocol;
//check if its a quake2 demo.
while(VFS_READ(f, &len, sizeof(len)) == sizeof(len))
{
len = LittleLong(len);
if (len > MAX_OVERALLMSGLEN)
break;
len--;
VFS_READ(f, &type, sizeof(type));
while (len >= 2 && (type == svcq2_stufftext) || (type == svcq2_print))
{
while (len > 0)
{
len--;
VFS_READ(f, &type, sizeof(type));
if (!type)
break;
}
if (len == 0)
continue;
len--;
VFS_READ(f, &type, sizeof(type));
}
if (len > 4 && type == svcq2_serverdata)
{
VFS_READ(f, &protocol, sizeof(protocol));
protocol = LittleLong(protocol);
if (protocol >= PROTOCOL_VERSION_Q2_DEMO_MIN && protocol <= PROTOCOL_VERSION_Q2_DEMO_MAX)
{
VFS_SEEK(f, start);
CL_PlayDemoStream(f, NULL, demoname, issyspath, DPB_QUAKE2, 0);
return;
}
break;
}
if (len)
VFS_SEEK(f, VFS_TELL(f)+len);
}
VFS_SEEK(f, start);
}
#endif
//it doesn't have a assumable extension, isn't q2, nor NQ. then it must be a QuakeWorld demo
//could also be .qwz or .dmz or whatever that nq extension is. we don't support either.
//mvd and qwd have no identifying markers, other than the extension.
if (!Q_strcasecmp(demoname + strlen(demoname) - 3, "mvd") ||
!Q_strcasecmp(demoname + strlen(demoname) - 6, "mvd.gz"))
CL_PlayDemoStream(f, NULL, demoname, issyspath, DPB_MVD, 0);
else
CL_PlayDemoStream(f, NULL, demoname, issyspath, DPB_QUAKEWORLD, 0);
CL_PlayDemoStream(f, NULL, demoname, issyspath, DPB_QUAKEWORLD, 0);
}
#ifdef WEBCLIENT
void CL_PlayDownloadedDemo(struct dl_download *dl)

View File

@ -2482,7 +2482,8 @@ void CL_DrawDebugPlane(float *normal, float dist, float r, float g, float b, qbo
{
// int oldents = cl_numvisedicts;
// cl_numvisedicts = 0;
BE_DrawWorld(NULL, NULL);
r_refdef.scenevis = NULL;
BE_DrawWorld(NULL);
cl_numstris = 0;
// cl_numvisedicts = oldents;
}
@ -2891,7 +2892,7 @@ void R_AddItemTimer(vec3_t shadoworg, float yaw, float radius, float percent)
s = R_RegisterShader("timershader", SUF_NONE,
"{\n"
"polygonoffset\n"
"program itemtimer\n"
"fte_program itemtimer\n"
"{\n"
"map $diffuse\n"
"blendfunc src_alpha one\n"

View File

@ -4686,6 +4686,7 @@ void Host_DoRunFile(hrf_t *f)
// if (f->flags & HRF_DOWNLOADED)
man->blockupdate = true;
BZ_Free(fdata);
PM_Shutdown();
FS_ChangeGame(man, true, true);
}
else

View File

@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
cvar_t cl_predict_extrapolate = CVARD("cl_predict_extrapolate", "", "If 1, enables prediction based upon partial input frames which can change over time resulting in a swimmy feel but does not need to interpolate. If 0, prediction will stay in the past and thus use only completed frames. Interpolation will then be used to smooth movement.\nThis cvar only applies when video and input frames are independant (ie: cl_netfps is set).");
cvar_t cl_predict_timenudge = CVARD("cl_predict_timenudge", "0", "A debug feature. You should normally leave this as 0. Nudges local player prediction into the future if positive (resulting in extrapolation), or into the past if negative (resulting in laggy interpolation). Value is in seconds, so small decimals are required. This cvar applies even if input frames are tied to video frames.");
cvar_t cl_predict_smooth = CVARD("cl_lerp_smooth", "2", "If 2, will act as 1 when playing demos and otherwise act as if set to 0.\nIf 1, interpolation will run in the past, resulting in really smooth movement at the cost of latency (even on bunchy german ISDNs).\nIf 0, interpolation will be based upon packet arrival times and may judder due to packet loss.");
cvar_t cl_predict_smooth = CVARD("cl_lerp_smooth", "2", "If 2, will act as 1 when playing demos/singleplayer and otherwise act as if set to 0 (ie: deathmatch).\nIf 1, interpolation will run in the past, resulting in really smooth movement at the cost of latency (even on bunchy german ISDNs).\nIf 0, interpolation will be based upon packet arrival times and may judder due to packet loss.");
cvar_t cl_nopred = CVAR("cl_nopred","0");
cvar_t cl_pushlatency = CVAR("pushlatency","-999");
@ -577,8 +577,8 @@ void CL_CalcClientTime(void)
//q2 has no drifting.
//q3 always drifts.
//nq+qw code can drift
//default is to drift in demos but not live (oh noes! added latency!)
if (cls.protocol == CP_QUAKE2 || (cls.protocol != CP_QUAKE3 && (!cl_predict_smooth.ival || (cl_predict_smooth.ival == 2 && !cls.demoplayback)) && cls.demoplayback != DPB_MVD))
//default is to drift in demos+SP but not live (oh noes! added latency!)
if (cls.protocol == CP_QUAKE2 || (cls.protocol != CP_QUAKE3 && (!cl_predict_smooth.ival || (cl_predict_smooth.ival == 2 && !(cls.demoplayback || cl.allocated_client_slots == 1))) && cls.demoplayback != DPB_MVD))
{ //no drift logic
float f;
f = cl.gametime - cl.oldgametime;

View File

@ -380,6 +380,16 @@ for a few moments
void SCR_CenterPrint (int pnum, char *str, qboolean skipgamecode)
{
cprint_t *p;
if (!str)
{
if (cl.intermissionmode == IM_NONE)
{
p = &scr_centerprint[pnum];
p->flags = 0;
p->time_off = 0;
}
return;
}
if (!skipgamecode)
{
#ifdef CSQC_DAT

View File

@ -15,7 +15,7 @@ texid_t GL_FindTextureFallback (const char *identifier, unsigned int flags, void
#else
cvar_t r_dodgytgafiles = CVARD("r_dodgytgafiles", "0", "Many old glquake engines had a buggy tga loader that ignored bottom-up flags. Naturally people worked around this and the world was plagued with buggy images. Most engines have now fixed the bug, but you can reenable it if you have bugged tga files.");
cvar_t r_dodgypcxfiles = CVARD("r_dodgypcxfiles", "0", "When enabled, this will ignore the palette stored within pcx files, for compatibility with quake2.");
cvar_t r_dodgymiptex = CVARD("r_dodgymiptex", "0", "When enabled, this will force regeneration of mipmaps, discarding mips1-4 like glquake did. This may eg solve fullbright issues with some maps, but may reduce distant detail levels.");
cvar_t r_dodgymiptex = CVARD("r_dodgymiptex", "1", "When enabled, this will force regeneration of mipmaps, discarding mips1-4 like glquake did. This may eg solve fullbright issues with some maps, but may reduce distant detail levels.");
char *r_defaultimageextensions =
#ifdef IMAGEFMT_DDS

File diff suppressed because it is too large Load Diff

View File

@ -383,7 +383,7 @@ typedef enum backendmode_e
BEM_STENCIL, //used for drawing shadow volumes to the stencil buffer.
BEM_DEPTHDARK, //a quick depth pass. textures used only for alpha test. additive textures still shown as normal.
BEM_CREPUSCULAR, //sky is special, everything else completely black
BEM_DEPTHNORM, //all opaque stuff drawn using 'depthnorm' shader
BEM_GBUFFER, //
BEM_FOG, //drawing a fog volume
BEM_LIGHT, //we have a valid light
} backendmode_t;
@ -429,7 +429,7 @@ typedef struct rendererinfo_s {
void (*BE_SubmitBatch)(struct batch_s *batch);
struct batch_s *(*BE_GetTempBatch)(void);
//Asks the backend to invoke DrawMeshChain for each surface, and to upload lightmaps as required
void (*BE_DrawWorld) (struct batch_s **worldbatches, qbyte *vis);
void (*BE_DrawWorld) (struct batch_s **worldbatches);
//called at init, force the display to the right defaults etc
void (*BE_Init)(void);
//Generates an optimised VBO, one for each texture on the map

View File

@ -1175,7 +1175,10 @@ void P_ParticleEffect_f(void)
}
else if (!strcmp(var, "shader"))
{
Q_strncpyz(ptype->texname, ptype->name, sizeof(ptype->texname));
if (*value)
Q_strncpyz(ptype->texname, value, sizeof(ptype->texname));
else
Q_strncpyz(ptype->texname, ptype->name, sizeof(ptype->texname));
buf = Cbuf_GetNext(Cmd_ExecLevel, true);
while (*buf && *buf <= ' ')
buf++; //no leading whitespace please.

View File

@ -268,8 +268,8 @@ extern "C" {
typedef struct quakeparms_s
{
char *basedir; //working directory
char *binarydir; //exe directory
const char *basedir; //working directory
const char *binarydir; //exe directory
const char *manifest; //linked manifest data (for installer functionality etc)
int argc;
const char **argv;

View File

@ -2942,7 +2942,8 @@ void Surf_DrawWorld (void)
if (r_refdef.flags & RDF_NOWORLDMODEL)
{
r_refdef.flags |= RDF_NOWORLDMODEL;
BE_DrawWorld(NULL, NULL);
r_refdef.scenevis = NULL;
BE_DrawWorld(NULL);
return;
}
if (!cl.worldmodel || cl.worldmodel->loadstate != MLS_LOADED)
@ -3055,7 +3056,8 @@ void Surf_DrawWorld (void)
P_DrawParticles ();
TRACE(("dbg: calling BE_DrawWorld\n"));
BE_DrawWorld(webostate->rbatches, surfvis);
r_refdef.scenevis = surfvis;
BE_DrawWorld(webostate->rbatches);
/*FIXME: move this away*/
if (cl.worldmodel->fromgame == fg_quake || cl.worldmodel->fromgame == fg_halflife)
@ -3155,7 +3157,8 @@ void Surf_DrawWorld (void)
}
TRACE(("dbg: calling BE_DrawWorld\n"));
BE_DrawWorld(cl.worldmodel->batches, surfvis);
r_refdef.scenevis = surfvis;
BE_DrawWorld(cl.worldmodel->batches);
Surf_PopChains(cl.worldmodel->batches);

View File

@ -267,6 +267,7 @@ typedef struct
float m_projection[16];
float m_view[16];
qbyte *scenevis; /*this is the vis that's currently being draw*/
mplane_t frustum[MAXFRUSTUMPLANES];
int frustum_numworldplanes; //all but far, which isn't culled because this wouldn't cover the entire screen.
@ -275,12 +276,12 @@ typedef struct
fogstate_t globalfog;
float hdr_value;
pxrect_t pxrect; /*vrect, but in pixels rather than virtual coords*/
qboolean externalview; /*draw external models and not viewmodels*/
int recurse; /*in a mirror/portal/half way through drawing something else*/
qboolean forcevis; /*if true, vis comes from the forcedvis field instead of recalculated*/
unsigned int flipcull; /*reflected/flipped view, requires inverted culling (should be set to SHADER_CULL_FLIPPED or 0)*/
qboolean useperspective; /*not orthographic*/
pxrect_t pxrect; /*vrect, but in pixels rather than virtual coords*/
qboolean externalview; /*draw external models and not viewmodels*/
int recurse; /*in a mirror/portal/half way through drawing something else*/
qboolean forcevis; /*if true, vis comes from the forcedvis field instead of recalculated*/
unsigned int flipcull; /*reflected/flipped view, requires inverted culling (should be set to SHADER_CULL_FLIPPED or 0)*/
qboolean useperspective; /*not orthographic*/
stereomethod_t stereomethod;
rtname_t rt_destcolour[R_MAX_RENDERTARGETS]; /*used for 2d. written by 3d*/
@ -289,7 +290,7 @@ typedef struct
rtname_t rt_ripplemap; /*read by 2d. used by 3d (internal ripplemap buffer used if not set)*/
rtname_t nearenvmap; /*provides a fallback endmap cubemap to render with*/
qbyte *forcedvis;
qbyte *forcedvis; /*set if forcevis is set*/
qboolean areabitsknown;
qbyte areabits[MAX_MAP_AREA_BYTES];
} refdef_t;
@ -595,12 +596,13 @@ extern cvar_t r_deluxemapping_cvar;
extern qboolean r_deluxemapping;
extern cvar_t r_softwarebanding_cvar;
extern qboolean r_softwarebanding;
extern cvar_t r_lightprepass_cvar;
extern int r_lightprepass; //0=off,1=16bit,2=32bit
#ifdef R_XFLIP
extern cvar_t r_xflip;
#endif
extern cvar_t r_lightprepass;
extern cvar_t gl_mindist, gl_maxdist;
extern cvar_t r_clear;
extern cvar_t gl_poly;

View File

@ -402,7 +402,8 @@ cvar_t r_noaliasshadows = CVARF ("r_noaliasshadows", "0", CVAR_ARCHIVE);
cvar_t r_shadows = CVARFD ("r_shadows", "0", CVAR_ARCHIVE, "Draw basic blob shadows underneath entities without using realtime lighting.");
cvar_t r_showbboxes = CVARD("r_showbboxes", "0", "Debugging. Shows bounding boxes. 1=ssqc, 2=csqc. Red=solid, Green=stepping/toss/bounce, Blue=onground.");
cvar_t r_showfields = CVARD("r_showfields", "0", "Debugging. Shows entity fields boxes (entity closest to crosshair). 1=ssqc, 2=csqc.");
cvar_t r_lightprepass = CVARFD("r_lightprepass", "0", CVAR_SHADERSYSTEM, "Experimental. Attempt to use a different lighting mechanism.");
cvar_t r_lightprepass_cvar = CVARFD("r_lightprepass", "0", CVAR_SHADERSYSTEM, "Experimental. Attempt to use a different lighting mechanism.");
int r_lightprepass;
cvar_t r_shadow_bumpscale_basetexture = CVARD ("r_shadow_bumpscale_basetexture", "0", "bumpyness scaler for generation of fallback normalmap textures from models");
cvar_t r_shadow_bumpscale_bumpmap = CVARD ("r_shadow_bumpscale_bumpmap", "4", "bumpyness scaler for _bump textures");
@ -776,7 +777,7 @@ void Renderer_Init(void)
Cvar_Register(&r_stains, GRAPHICALNICETIES);
Cvar_Register(&r_stainfadetime, GRAPHICALNICETIES);
Cvar_Register(&r_stainfadeammount, GRAPHICALNICETIES);
Cvar_Register(&r_lightprepass, GLRENDEREROPTIONS);
Cvar_Register(&r_lightprepass_cvar, GLRENDEREROPTIONS);
Cvar_Register (&r_coronas, GRAPHICALNICETIES);
Cvar_Register (&r_coronas_occlusion, GRAPHICALNICETIES);
Cvar_Register (&r_coronas_mindist, GRAPHICALNICETIES);
@ -1249,9 +1250,6 @@ qboolean R_ApplyRenderer_Load (rendererstate_t *newr)
pmove.numphysent = 0;
pmove.physents[0].model = NULL;
r_softwarebanding = r_softwarebanding_cvar.ival;
r_deluxemapping = r_deluxemapping_cvar.ival;
vid.dpi_x = 0;
vid.dpi_y = 0;
@ -1332,6 +1330,10 @@ TRACE(("dbg: R_ApplyRenderer: Palette loaded\n"));
}
TRACE(("dbg: R_ApplyRenderer: vid applied\n"));
r_softwarebanding = false;
r_deluxemapping = false;
r_lightprepass = false;
W_LoadWadFile("gfx.wad");
TRACE(("dbg: R_ApplyRenderer: wad loaded\n"));
Image_Init();

View File

@ -191,7 +191,7 @@ static struct batch_s *Headless_BE_GetTempBatch (void)
{
return NULL;
}
static void Headless_BE_DrawWorld (struct batch_s **worldbatches, qbyte *vis)
static void Headless_BE_DrawWorld (struct batch_s **worldbatches)
{
}
static void Headless_BE_Init (void)

View File

@ -5511,10 +5511,11 @@ void COM_Init (void)
COM_InitWorkerThread();
#endif
Cmd_AddCommand ("path", COM_Path_f); //prints a list of current search paths.
Cmd_AddCommand ("dir", COM_Dir_f); //q3 like
Cmd_AddCommand ("flocate", COM_Locate_f); //prints the pak or whatever where this file can be found.
Cmd_AddCommand ("version", COM_Version_f); //prints the pak or whatever where this file can be found.
Cmd_AddCommandD("pkg", PM_Command_f, "Provides a way to install / list / disable / purge packages via the console.");
Cmd_AddCommandD("path", COM_Path_f, "prints a list of current search paths.");
Cmd_AddCommandD("dir", COM_Dir_f, "Displays filesystem listings. Accepts wildcards."); //q3 like
Cmd_AddCommandD("flocate", COM_Locate_f, "Searches for a named file, and displays where it can be found in the OS's filesystem"); //prints the pak or whatever where this file can be found.
Cmd_AddCommandD("version", COM_Version_f, "Reports engine revision and optional compile-time settings."); //prints the pak or whatever where this file can be found.
#ifdef _DEBUG
Cmd_AddCommand ("loopme", COM_LoopMe_f);

View File

@ -639,6 +639,7 @@ typedef struct
void FS_Manifest_Free(ftemanifest_t *man);
ftemanifest_t *FS_Manifest_Parse(const char *fname, const char *data);
void PM_Shutdown(void);
void PM_Command_f(void);
void COM_InitFilesystem (void); //does not set up any gamedirs.
qboolean FS_DownloadingPackage(void);
@ -704,7 +705,7 @@ int version_number(void);
char *version_string(void);
void TL_InitLanguages(char *langpath); //langpath is where the .po files can be found
void TL_InitLanguages(const char *langpath); //langpath is where the .po files can be found
void TL_Shutdown(void);
void T_FreeStrings(void);
char *T_GetString(int num);

View File

@ -3989,7 +3989,7 @@ static qboolean FS_DirHasAPackage(char *basedir, ftemanifest_t *man)
}
//just check each possible file, see if one is there.
static qboolean FS_DirHasGame(char *basedir, int gameidx)
static qboolean FS_DirHasGame(const char *basedir, int gameidx)
{
int j;
vfsfile_t *f;
@ -4008,7 +4008,7 @@ static qboolean FS_DirHasGame(char *basedir, int gameidx)
}
//check em all
static int FS_IdentifyDefaultGameFromDir(char *basedir)
static int FS_IdentifyDefaultGameFromDir(const char *basedir)
{
int i;
for (i = 0; gamemode_info[i].argname; i++)
@ -5411,6 +5411,7 @@ void FS_ChangeGame_f(void)
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;
}
@ -5450,15 +5451,15 @@ void FS_ChangeMod_f(void)
arg = Cmd_Argv(i++);
if (!strcmp(arg, "package"))
{
if (packages >= countof(packagespaths)-1) //must leave space for one, as a terminator.
break;
arg = Cmd_Argv(i++);
packagespaths[packages].url = Z_StrDup(arg);
if (!FS_PathURLCache(packagespaths[packages].url, cachename, sizeof(cachename)))
break;
packagespaths[packages].path = Z_StrDup(cachename);
packages++;
if (packages == countof(packagespaths)) //must leave space for one, as a terminator.
continue;
if (FS_PathURLCache(arg, cachename, sizeof(cachename)))
{
packagespaths[packages].url = Z_StrDup(arg);
packagespaths[packages].path = Z_StrDup(cachename);
packages++;
}
}
else if (!strcmp(arg, "prefix"))
{

View File

@ -108,12 +108,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define PROTOCOL_VERSION_QW 28
#define PROTOCOL_VERSION_Q2_DEMO_MIN 26
#define PROTOCOL_VERSION_Q2_MIN 31
#define PROTOCOL_VERSION_Q2 34
#define PROTOCOL_VERSION_Q2_DEMO_MIN 26 //we can parse this server
#define PROTOCOL_VERSION_Q2_MIN 31 //we can join these outdated servers
#define PROTOCOL_VERSION_Q2 34 //we host this
#define PROTOCOL_VERSION_R1Q2 35
#define PROTOCOL_VERSION_Q2PRO 36
#define PROTOCOL_VERSION_Q2_DEMO_MAX PROTOCOL_VERSION_Q2PRO
//=========================================
#define PORT_NQSERVER 26000

View File

@ -174,7 +174,7 @@ void NPQTV_Sys_MainLoop(void);
#define UPD_STABLE 2
#define UPD_TESTING 3
#if defined(WEBCLIENT) && defined(_WIN32)
#if defined(WEBCLIENT) && defined(_WIN32) && !defined(SERVERONLY)
int StartLocalServer(int close);
#define HAVEAUTOUPDATE

View File

@ -89,7 +89,7 @@ int TL_FindLanguage(const char *lang)
}
//need to set up default languages for any early prints before cvars are inited.
void TL_InitLanguages(char *newlangpath)
void TL_InitLanguages(const char *newlangpath)
{
int i;
char *lang;

View File

@ -3532,7 +3532,7 @@ void D3D11BE_DoneShadows(void)
}
#endif
void D3D11BE_DrawWorld (batch_t **worldbatches, qbyte *vis)
void D3D11BE_DrawWorld (batch_t **worldbatches)
{
batch_t *batches[SHADER_SORT_COUNT];
RSpeedLocals();
@ -3559,7 +3559,7 @@ void D3D11BE_DrawWorld (batch_t **worldbatches, qbyte *vis)
shaderstate.curdlight = NULL;
BE_GenModelBatches(batches, shaderstate.curdlight, BEM_STANDARD);
if (vis)
if (r_refdef.scenevis)
{
BE_UploadLightmaps(false);
@ -3573,7 +3573,7 @@ void D3D11BE_DrawWorld (batch_t **worldbatches, qbyte *vis)
r_worldentity.axis[2][2] = 1;
#ifdef RTLIGHTS
if (vis && r_shadow_realtime_world.ival)
if (r_refdef.scenevis && r_shadow_realtime_world.ival)
shaderstate.identitylighting = r_shadow_realtime_world_lightmaps.value;
else
#endif
@ -3590,7 +3590,7 @@ void D3D11BE_DrawWorld (batch_t **worldbatches, qbyte *vis)
#ifdef RTLIGHTS
RSpeedRemark();
D3D11BE_SelectEntity(&r_worldentity);
Sh_DrawLights(vis);
Sh_DrawLights(r_refdef.scenevis);
RSpeedEnd(RSPEED_STENCILSHADOWS);
#endif

View File

@ -3459,7 +3459,7 @@ void D3D9BE_RenderShadowBuffer(unsigned int numverts, IDirect3DVertexBuffer9 *vb
}
#endif
void D3D9BE_DrawWorld (batch_t **worldbatches, qbyte *vis)
void D3D9BE_DrawWorld (batch_t **worldbatches)
{
batch_t *batches[SHADER_SORT_COUNT];
RSpeedLocals();
@ -3514,11 +3514,11 @@ void D3D9BE_DrawWorld (batch_t **worldbatches, qbyte *vis)
RSpeedEnd(RSPEED_WORLD);
#ifdef RTLIGHTS
if (vis)
if (r_refdef.scenevis)
{
RSpeedRemark();
D3D9BE_SelectEntity(&r_worldentity);
Sh_DrawLights(vis);
Sh_DrawLights(r_refdef.scenevis);
RSpeedEnd(RSPEED_STENCILSHADOWS);
}
#endif

View File

@ -724,8 +724,8 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
(tex->upperoverlay && (tex->upperoverlay->status == TEX_LOADING || tex->upperoverlay->status == TEX_LOADED)))
return shader;
}
if (shader->prog && (shader->prog->supportedpermutations & PERMUTATION_UPPERLOWER) && !h2playertranslations)
{ //this shader can do permutations. this means we can generate only a black image, with separate top+bottom textures.
if ((shader->flags & SHADER_HASTOPBOTTOM) && !h2playertranslations)
{ //this shader will try to do top+bottom colours. this means we can generate only a black image, with separate top+bottom textures.
tc = 0xfe000000;
bc = 0xfe000000;
generateupperlower = true;

View File

@ -96,10 +96,8 @@ struct {
program_t *programfixedemu[8];
qboolean initeddepthnorm;
const shader_t *depthnormshader;
texid_t tex_normals;
texid_t tex_diffuse;
texid_t tex_gbuf_normals;
texid_t tex_gbuf_diffuse;
int fbo_current; //the one currently being rendered to
texid_t tex_sourcecol; /*this is used by $sourcecolour tgen*/
texid_t tex_sourcedepth;
@ -1409,6 +1407,19 @@ void GLBE_DestroyFBOs(void)
Image_DestroyTexture(shaderstate.temptexture);
shaderstate.temptexture = r_nulltex;
}
//nuke deferred rendering stuff
if (shaderstate.tex_gbuf_diffuse)
{
Image_DestroyTexture(shaderstate.tex_gbuf_diffuse);
shaderstate.tex_gbuf_diffuse = r_nulltex;
}
if (shaderstate.tex_gbuf_normals)
{
Image_DestroyTexture(shaderstate.tex_gbuf_normals);
shaderstate.tex_gbuf_normals = r_nulltex;
}
}
void GLBE_Shutdown(void)
@ -4042,10 +4053,8 @@ static void DrawMeshes(void)
BE_LegacyLighting();
#endif
break;
case BEM_DEPTHNORM:
altshader = shaderstate.curshader->bemoverrides[bemoverride_prelight];
if (!altshader)
altshader = shaderstate.depthnormshader;
case BEM_GBUFFER:
altshader = shaderstate.curshader->bemoverrides[bemoverride_gbuffer];
if (altshader && altshader->prog)
{
shaderstate.pendingcolourvbo = shaderstate.sourcevbo->colours[0].gl.vbo;
@ -4276,7 +4285,6 @@ static void DrawMeshes(void)
#ifndef GLSLONLY
else
{
GL_DeSelectProgram();
while (passno < shaderstate.curshader->numpasses)
{
p = &shaderstate.curshader->passes[passno];
@ -4284,7 +4292,23 @@ static void DrawMeshes(void)
// if (p->flags & SHADER_PASS_DETAIL)
// continue;
DrawPass(p);
if (p->prog)
{
shaderstate.pendingcolourvbo = shaderstate.sourcevbo->colours[0].gl.vbo;
shaderstate.pendingcolourpointer = shaderstate.sourcevbo->colours[0].gl.addr;
shaderstate.colourarraytype = shaderstate.sourcevbo->colours_bytes?GL_UNSIGNED_BYTE:GL_FLOAT;
shaderstate.pendingtexcoordparts[0] = 2;
shaderstate.pendingtexcoordvbo[0] = shaderstate.sourcevbo->texcoord.gl.vbo;
shaderstate.pendingtexcoordpointer[0] = shaderstate.sourcevbo->texcoord.gl.addr;
BE_RenderMeshProgram(shaderstate.curshader, p, p->prog);
}
else
{
GL_DeSelectProgram();
DrawPass(p);
}
}
}
if (shaderstate.curbatch->fog && shaderstate.curbatch->fog->shader)
@ -5339,8 +5363,9 @@ void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destco
}
*/
void GLBE_DrawLightPrePass(qbyte *vis)
void GLBE_DrawLightPrePass(void)
{
qboolean redefine = false;
/*
walls(bumps) -> normalbuffer
lights+normalbuffer -> lightlevelbuffer
@ -5349,69 +5374,50 @@ void GLBE_DrawLightPrePass(qbyte *vis)
normalbuffer contains depth in the alpha channel. an actual depthbuffer is also generated at this time, which is used for depth test stuff but not as a shader input.
*/
int oldfbo;
if (!shaderstate.initeddepthnorm)
{
shaderstate.initeddepthnorm = true;
shaderstate.depthnormshader = R_RegisterShader("lpp_depthnorm", SUF_NONE,
"{\n"
"program lpp_depthnorm\n"
"{\n"
"map $normalmap\n"
"tcgen base\n"
"}\n"
"}\n"
);
}
if (!shaderstate.depthnormshader)
{
Con_Printf("%s requires content support\n", r_lightprepass.name);
r_lightprepass.ival = 0;
return;
}
/*do portals*/
BE_SelectMode(BEM_STANDARD);
GLBE_SubmitMeshes(cl.worldmodel->batches, SHADER_SORT_PORTAL, SHADER_SORT_PORTAL);
BE_SelectMode(BEM_DEPTHNORM);
if (!shaderstate.depthnormshader)
BE_SelectMode(BEM_GBUFFER);
if (!TEXVALID(shaderstate.tex_gbuf_normals) || vid.fbpwidth != shaderstate.tex_gbuf_normals->width || vid.fbpheight != shaderstate.tex_gbuf_normals->height)
{
BE_SelectMode(BEM_STANDARD);
return;
if (!shaderstate.tex_gbuf_normals)
{
shaderstate.tex_gbuf_normals = Image_CreateTexture("***prepass normals***", NULL, 0);
qglGenTextures(1, &shaderstate.tex_gbuf_normals->num);
}
shaderstate.tex_gbuf_normals->width = vid.fbpwidth;
shaderstate.tex_gbuf_normals->height = vid.fbpheight;
redefine = true;
}
if (!TEXVALID(shaderstate.tex_gbuf_diffuse) || vid.fbpwidth != shaderstate.tex_gbuf_diffuse->width || vid.fbpheight != shaderstate.tex_gbuf_diffuse->height)
{
if (!shaderstate.tex_gbuf_diffuse)
{
shaderstate.tex_gbuf_diffuse = Image_CreateTexture("***prepass diffuse***", NULL, 0);
qglGenTextures(1, &shaderstate.tex_gbuf_diffuse->num);
}
shaderstate.tex_gbuf_diffuse->width = vid.fbpwidth;
shaderstate.tex_gbuf_diffuse->height = vid.fbpheight;
redefine = true;
}
if (!TEXVALID(shaderstate.tex_normals))
//something changed, redefine the textures.
if (redefine)
{
shaderstate.tex_normals = Image_CreateTexture("***prepass normals***", NULL, 0);
qglGenTextures(1, &shaderstate.tex_normals->num);
r_lightprepass.modified = true;
}
if (r_lightprepass.modified)
{
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_normals);
qglTexImage2D(GL_TEXTURE_2D, 0, (r_lightprepass.ival==2)?GL_RGBA32F_ARB:GL_RGBA16F_ARB, vid.pixelwidth, vid.pixelheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
r_lightprepass.modified = false;
}
if (!TEXVALID(shaderstate.tex_diffuse))
{
shaderstate.tex_diffuse = Image_CreateTexture("***prepass diffuse***", NULL, 0);
qglGenTextures(1, &shaderstate.tex_diffuse->num);
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_diffuse);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, vid.pixelwidth, vid.pixelheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_gbuf_diffuse);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, vid.fbpwidth, vid.fbpheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_normals);
qglTexImage2D(GL_TEXTURE_2D, 0, (r_lightprepass.ival==2)?GL_RGBA32F_ARB:GL_RGBA16F_ARB, vid.pixelwidth, vid.pixelheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
r_lightprepass.modified = false;
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_gbuf_normals);
qglTexImage2D(GL_TEXTURE_2D, 0, (r_lightprepass==2)?GL_RGBA32F_ARB:GL_RGBA16F_ARB, vid.fbpwidth, vid.fbpheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
/*set the FB up to draw surface info*/
oldfbo = GLBE_FBO_Update(&shaderstate.fbo_lprepass, FBO_RB_DEPTH, &shaderstate.tex_normals, 1, r_nulltex, vid.pixelwidth, vid.pixelheight, 0);
oldfbo = GLBE_FBO_Update(&shaderstate.fbo_lprepass, FBO_RB_DEPTH, &shaderstate.tex_gbuf_normals, 1, r_nulltex, vid.fbpwidth, vid.fbpheight, 0);
GL_ForceDepthWritable();
//FIXME: should probably clear colour buffer too.
qglClear(GL_DEPTH_BUFFER_BIT);
@ -5426,8 +5432,8 @@ void GLBE_DrawLightPrePass(qbyte *vis)
GLBE_SubmitMeshes(cl.worldmodel->batches, SHADER_SORT_OPAQUE, SHADER_SORT_OPAQUE);
/*reconfigure - now drawing diffuse light info using the previous fb image as a source image*/
GLBE_FBO_Sources(shaderstate.tex_normals, r_nulltex);
GLBE_FBO_Update(&shaderstate.fbo_lprepass, FBO_RB_DEPTH, &shaderstate.tex_diffuse, 1, r_nulltex, vid.pixelwidth, vid.pixelheight, 0);
GLBE_FBO_Sources(shaderstate.tex_gbuf_normals, r_nulltex);
GLBE_FBO_Update(&shaderstate.fbo_lprepass, FBO_RB_DEPTH, &shaderstate.tex_gbuf_diffuse, 1, r_nulltex, vid.fbpwidth, vid.fbpheight, 0);
BE_SelectMode(BEM_STANDARD);
qglClearColor (0,0,0,1);
@ -5439,8 +5445,9 @@ void GLBE_DrawLightPrePass(qbyte *vis)
/*final reconfigure - now drawing final surface data onto true framebuffer*/
GLBE_FBO_Pop(oldfbo);
GLBE_FBO_Sources(shaderstate.tex_diffuse, r_nulltex);
qglDrawBuffer(GL_BACK);
GLBE_FBO_Sources(shaderstate.tex_gbuf_diffuse, r_nulltex);
if (!oldfbo)
qglDrawBuffer(GL_BACK);
/*now draw the postlight passes (this includes blended stuff which will NOT be lit)*/
GLBE_SelectEntity(&r_worldentity);
@ -5449,14 +5456,14 @@ void GLBE_DrawLightPrePass(qbyte *vis)
#ifdef RTLIGHTS
/*regular lighting now*/
GLBE_SelectEntity(&r_worldentity);
Sh_DrawLights(vis);
Sh_DrawLights(r_refdef.scenevis);
#endif
GLBE_FBO_Sources(r_nulltex, r_nulltex);
qglClearColor (1,0,0,1);
}
void GLBE_DrawWorld (batch_t **worldbatches, qbyte *vis)
void GLBE_DrawWorld (batch_t **worldbatches)
{
#ifdef RTLIGHTS
extern cvar_t r_shadow_realtime_world, r_shadow_realtime_world_lightmaps;
@ -5535,9 +5542,9 @@ void GLBE_DrawWorld (batch_t **worldbatches, qbyte *vis)
// shaderstate.identitylightmap *= 1<<gl_overbright.ival;
#ifdef RTLIGHTS
if (r_lightprepass.ival)
if (r_lightprepass)
{
GLBE_DrawLightPrePass(vis);
GLBE_DrawLightPrePass();
}
else
#endif
@ -5557,7 +5564,7 @@ void GLBE_DrawWorld (batch_t **worldbatches, qbyte *vis)
RSpeedRemark();
TRACE(("GLBE_DrawWorld: drawing lights\n"));
GLBE_SelectEntity(&r_worldentity);
Sh_DrawLights(vis);
Sh_DrawLights(r_refdef.scenevis);
RSpeedEnd(RSPEED_STENCILSHADOWS);
TRACE(("GLBE_DrawWorld: lights drawn\n"));
}

View File

@ -59,6 +59,10 @@ Draw_Init
*/
void GLDraw_Init (void)
{
//figure out which extra features we can support on these drivers.
r_deluxemapping = r_deluxemapping_cvar.ival;
r_lightprepass = r_lightprepass_cvar.ival && sh_config.progs_supported;
r_softwarebanding = r_softwarebanding_cvar.ival && sh_config.progs_supported;
if (gl_config.gles && gl_config.glversion < 3.0)
r_softwarebanding = false;
@ -115,6 +119,9 @@ void GLDraw_DeInit (void)
Sh_Shutdown();
#endif
Shader_Shutdown();
GLBE_Shutdown(); //to release its images.
Image_Shutdown();
}

View File

@ -195,7 +195,7 @@ mesh_t flashblend_mesh;
mesh_t flashblend_fsmesh;
shader_t *occluded_shader;
shader_t *flashblend_shader;
shader_t *lpplight_shader;
shader_t *lpplight_shader[LSHADER_MODES];
void R_GenerateFlashblendTexture(void)
{
@ -275,7 +275,7 @@ void R_InitFlashblends(void)
"}\n"
"}\n"
);
lpplight_shader = NULL;
memset(lpplight_shader, 0, sizeof(lpplight_shader));
}
static qboolean R_BuildDlightMesh(dlight_t *light, float colscale, float radscale, int dtype)
@ -520,18 +520,30 @@ void R_RenderDlights (void)
}
qboolean Sh_GenerateShadowMap(dlight_t *l);
void R_GenDlightMesh(struct batch_s *batch)
{
static mesh_t *meshptr;
dlight_t *l = cl_dlights + batch->surf_first;
BE_SelectDLight(l, l->color, l->axis, 0);
int lightflags = batch->surf_count;
BE_SelectDLight(l, l->color, l->axis, lightflags);
if (lightflags & LSHADER_SMAP)
{
if (!Sh_GenerateShadowMap(l))
{
batch->meshes = 0;
return;
}
BE_SelectEntity(&r_worldentity);
BE_SelectMode(BEM_STANDARD);
}
if (!R_BuildDlightMesh (l, 2, 1, 2))
{
int i;
static vec2_t s[4] = {{1, -1}, {-1, -1}, {-1, 1}, {1, 1}};
batch->flags |= BEF_FORCENODEPTH;
for (i = 0; i < 4; i++)
{
VectorMA(r_origin, 32, vpn, flashblend_vcoords[i]);
@ -552,21 +564,37 @@ void R_GenDlightBatches(batch_t *batches[])
int i, j, sort;
dlight_t *l;
batch_t *b;
if (!r_lightprepass.ival)
int lmode;
if (!r_lightprepass)
return;
if (!lpplight_shader)
lpplight_shader = R_RegisterShader("lpp_light", SUF_NONE,
if (!lpplight_shader[0])
{
lpplight_shader[0] = R_RegisterShader("lpp_light", SUF_NONE,
"{\n"
"program lpp_light\n"
"{\n"
"map $sourcecolour\n"
"blendfunc gl_one gl_one\n"
"nodepthtest\n"
"}\n"
"surfaceparm nodlight\n"
"lpp_light\n"
"}\n"
);
lpplight_shader[LSHADER_SMAP] = R_RegisterShader("lpp_light#PCF", SUF_NONE,
"{\n"
"program lpp_light\n"
"{\n"
"map $sourcecolour\n"
"blendfunc gl_one gl_one\n"
"nodepthtest\n"
"}\n"
"surfaceparm nodlight\n"
"lpp_light\n"
"}\n"
);
}
l = cl_dlights+rtlights_first;
for (i=rtlights_first; i<rtlights_max; i++, l++)
@ -577,12 +605,19 @@ void R_GenDlightBatches(batch_t *batches[])
if (R_CullSphere(l->origin, l->radius))
continue;
lmode = 0;
if (!(((i >= RTL_FIRST)?!r_shadow_realtime_world_shadows.ival:!r_shadow_realtime_dlight_shadows.ival) || l->flags & LFLAG_NOSHADOWS))
lmode |= LSHADER_SMAP;
// if (TEXLOADED(l->cubetexture))
// lmode |= LSHADER_CUBE;
b = BE_GetTempBatch();
if (!b)
return;
b->flags = 0;
sort = lpplight_shader->sort;
b->shader = lpplight_shader[lmode];
sort = b->shader->sort;
b->buildmeshes = R_GenDlightMesh;
b->ent = &r_worldentity;
b->mesh = NULL;
@ -590,10 +625,10 @@ void R_GenDlightBatches(batch_t *batches[])
b->meshes = 1;
b->skin = NULL;
b->texture = NULL;
b->shader = lpplight_shader;
for (j = 0; j < MAXRLIGHTMAPS; j++)
b->lightmap[j] = -1;
b->surf_first = i;
b->surf_count = lmode;
b->flags |= BEF_NOSHADOWS;
b->vbo = NULL;
b->next = batches[sort];

View File

@ -1882,6 +1882,8 @@ void GLR_RenderView (void)
}
else if ((r_refdef.flags & (RDF_ALLPOSTPROC)) || renderscale != 1)
{
unsigned int rtflags = IF_NOMIPMAP|IF_CLAMP|IF_RENDERTARGET;
r_refdef.flags |= RDF_RENDERSCALE;
//the game needs to be drawn to a texture for post processing
@ -1896,8 +1898,19 @@ void GLR_RenderView (void)
vid.fbpheight = (r_refdef.vrect.height * vid.pixelheight) / vid.height;
}
vid.fbpwidth *= renderscale;
vid.fbpheight *= renderscale;
if (renderscale < 0)
{
renderscale = -renderscale;
rtflags |= IF_NEAREST;
vid.fbpwidth *= renderscale;
vid.fbpheight *= renderscale;
}
else
{
rtflags |= IF_LINEAR;
vid.fbpwidth *= renderscale;
vid.fbpheight *= renderscale;
}
//well... err... meh.
vid.fbpwidth = bound(1, vid.fbpwidth, sh_config.texture_maxsize);
@ -1906,7 +1919,7 @@ void GLR_RenderView (void)
vid.fbvwidth = vid.fbpwidth;
vid.fbvheight = vid.fbpheight;
sourcetex = R2D_RT_Configure("rt/$lastgameview", vid.fbpwidth, vid.fbpheight, /*(r_refdef.flags&RDF_BLOOM)?TF_RGBA16F:*/TF_RGBA32, RT_IMAGEFLAGS);
sourcetex = R2D_RT_Configure("rt/$lastgameview", vid.fbpwidth, vid.fbpheight, /*(r_refdef.flags&RDF_BLOOM)?TF_RGBA16F:*/TF_RGBA32, rtflags);
oldfbo = GLBE_FBO_Update(&fbo_gameview, FBO_RB_DEPTH, &sourcetex, 1, r_nulltex, vid.fbpwidth, vid.fbpheight, 0);
dofbo = true;

View File

@ -231,6 +231,7 @@ static struct
vec3_t refractcolour;
vec3_t reflectcolour;
float wateralpha;
qboolean droppass;
} parsestate;
typedef struct shaderkey_s
@ -292,13 +293,13 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr)
if (*token == '#')
conditiontrue = conditiontrue == !!Shader_FloatArgument(shader, token);
else if (!Q_stricmp(token, "lpp"))
conditiontrue = conditiontrue == r_lightprepass.ival;
conditiontrue = conditiontrue == r_lightprepass;
else if (!Q_stricmp(token, "lightmap"))
conditiontrue = conditiontrue == !r_fullbright.value;
else if (!Q_stricmp(token, "deluxmap"))
conditiontrue = conditiontrue == r_deluxemapping;
else if (!Q_stricmp(token, "softwarebanding"))
conditiontrue = conditiontrue == r_softwarebanding && sh_config.progs_supported;
conditiontrue = conditiontrue == r_softwarebanding;
//normalmaps are generated if they're not already known.
else if (!Q_stricmp(token, "normalmap"))
@ -1966,33 +1967,54 @@ static void Shader_SLProgramName (shader_t *shader, shaderpass_t *pass, char **p
*/
char *programbody;
char *hash;
program_t *newprog;
programbody = Shader_ParseBody(shader->name, ptr);
if (programbody)
{
shader->prog = BZ_Malloc(sizeof(*shader->prog));
memset(shader->prog, 0, sizeof(*shader->prog));
shader->prog->refs = 1;
if (!Shader_LoadPermutations(shader->name, shader->prog, programbody, qrtype, 0, NULL))
newprog = BZ_Malloc(sizeof(*newprog));
memset(newprog, 0, sizeof(*newprog));
newprog->refs = 1;
if (!Shader_LoadPermutations(shader->name, newprog, programbody, qrtype, 0, NULL))
{
BZ_Free(shader->prog);
shader->prog = NULL;
BZ_Free(newprog);
newprog = NULL;
}
BZ_Free(programbody);
return;
}
hash = strchr(shader->name, '#');
if (hash)
{
//pass the # postfixes from the shader name onto the generic glsl to use
char newname[512];
Q_snprintfz(newname, sizeof(newname), "%s%s", Shader_ParseExactString(ptr), hash);
shader->prog = Shader_FindGeneric(newname, qrtype);
}
else
shader->prog = Shader_FindGeneric(Shader_ParseExactString(ptr), qrtype);
{
hash = strchr(shader->name, '#');
if (hash)
{
//pass the # postfixes from the shader name onto the generic glsl to use
char newname[512];
Q_snprintfz(newname, sizeof(newname), "%s%s", Shader_ParseExactString(ptr), hash);
newprog = Shader_FindGeneric(newname, qrtype);
}
else
newprog = Shader_FindGeneric(Shader_ParseExactString(ptr), qrtype);
}
if (pass)
{
if (pass->numMergedPasses)
{
Shader_ReleaseGeneric(newprog);
Con_DPrintf("shader %s: program defined after first texture map\n", shader->name);
}
else
{
Shader_ReleaseGeneric(pass->prog);
pass->prog = newprog;
}
}
else
{
Shader_ReleaseGeneric(shader->prog);
shader->prog = newprog;
}
}
static void Shader_GLSLProgramName (shader_t *shader, shaderpass_t *pass, char **ptr)
@ -2301,8 +2323,8 @@ static void Shader_BEMode(shader_t *shader, shaderpass_t *pass, char **ptr)
mode = bemoverride_depthonly;
else if (!Q_stricmp(token, "depthdark"))
mode = bemoverride_depthdark;
else if (!Q_stricmp(token, "prelight"))
mode = bemoverride_prelight;
else if (!Q_stricmp(token, "gbuffer") || !Q_stricmp(token, "prelight"))
mode = bemoverride_gbuffer;
else if (!Q_stricmp(token, "fog"))
mode = bemoverride_fog;
else
@ -2541,11 +2563,44 @@ static qboolean Shaderpass_MapGen (shader_t *shader, shaderpass_t *pass, char *t
return true;
}
shaderpass_t *Shaderpass_DefineMap(shader_t *shader, shaderpass_t *pass)
{
//'map foo' works a bit differently when there's a program in the same pass.
//instead of corrupting the previous one, it collects multiple maps so that {prog foo;map t0;map t1; map t2; blendfunc add} can work as expected
if (pass->prog)
{
if (pass->numMergedPasses==0)
pass->numMergedPasses++;
else
{ //FIXME: bounds check!
if (shader->numpasses == SHADER_PASS_MAX || shader->numpasses == SHADER_TMU_MAX)
{
Con_DPrintf (CON_WARNING "Shader %s has too many texture passes.\n", shader->name);
parsestate.droppass = true;
}
// else if (shader->numpasses == be_maxpasses)
// parsestate.droppass = true;
else
{
pass->numMergedPasses++;
shader->numpasses++;
}
pass = shader->passes+shader->numpasses-1;
memset(pass, 0, sizeof(*pass));
}
}
else
pass->numMergedPasses = 1;
return pass;
}
static void Shaderpass_Map (shader_t *shader, shaderpass_t *pass, char **ptr)
{
int flags;
char *token;
pass = Shaderpass_DefineMap(shader, pass);
pass->anim_frames[0] = r_nulltex;
token = Shader_ParseString (ptr);
@ -2703,6 +2758,53 @@ static void Shaderpass_VideoMap (shader_t *shader, shaderpass_t *pass, char **pt
#endif
}
static void Shaderpass_SLProgramName (shader_t *shader, shaderpass_t *pass, char **ptr, int qrtype)
{
/*accepts:
program
{
BLAH
}
where BLAH is both vertex+frag with #ifdefs
or
program fname
on one line.
*/
//char *programbody;
char *hash;
/*programbody = Shader_ParseBody(shader->name, ptr);
if (programbody)
{
shader->prog = BZ_Malloc(sizeof(*shader->prog));
memset(shader->prog, 0, sizeof(*shader->prog));
shader->prog->refs = 1;
if (!Shader_LoadPermutations(shader->name, shader->prog, programbody, qrtype, 0, NULL))
{
BZ_Free(shader->prog);
shader->prog = NULL;
}
BZ_Free(programbody);
return;
}*/
hash = strchr(shader->name, '#');
if (hash)
{
//pass the # postfixes from the shader name onto the generic glsl to use
char newname[512];
Q_snprintfz(newname, sizeof(newname), "%s%s", Shader_ParseExactString(ptr), hash);
pass->prog = Shader_FindGeneric(newname, qrtype);
}
else
pass->prog = Shader_FindGeneric(Shader_ParseExactString(ptr), qrtype);
}
static void Shaderpass_ProgramName (shader_t *shader, shaderpass_t *pass, char **ptr)
{
Shaderpass_SLProgramName(shader,pass,ptr,qrenderer);
}
static void Shaderpass_RGBGen (shader_t *shader, shaderpass_t *pass, char **ptr)
{
char *token;
@ -3250,6 +3352,8 @@ static shaderkey_t shaderpasskeys[] =
{"alphamask", Shaderpass_AlphaMask, "rscript"},//for alienarena
{"detail", Shaderpass_Detail, "rscript"},
{"program", Shaderpass_ProgramName, "fte"},
/*doom3 compat*/
{"blend", Shaderpass_BlendFunc, "doom3"},
{"maskcolor", Shaderpass_MaskColor, "doom3"},
@ -3280,6 +3384,12 @@ void Shader_FreePass (shaderpass_t *pass)
pass->cin = NULL;
}
#endif
if (pass->prog)
{
Shader_ReleaseGeneric(pass->prog);
pass->prog = NULL;
}
}
void Shader_ReleaseGeneric(program_t *prog)
@ -3651,32 +3761,132 @@ void Shader_SetBlendmode (shaderpass_t *pass)
pass->blendmode = (pass->texgen == T_GEN_LIGHTMAP)?PBM_OVERBRIGHT:PBM_MODULATE;
}
void Shader_FixupProgPasses(shader_t *shader, shaderpass_t *pass)
{
int i;
int maxpasses = SHADER_PASS_MAX - (pass-shader->passes);
struct
{
int gen;
unsigned int flags;
} defaulttgen[] =
{
//light
{T_GEN_SHADOWMAP, 0}, //1
{T_GEN_LIGHTCUBEMAP, 0}, //2
//material
{T_GEN_DIFFUSE, SHADER_HASDIFFUSE}, //3
{T_GEN_NORMALMAP, SHADER_HASNORMALMAP}, //4
{T_GEN_SPECULAR, SHADER_HASGLOSS}, //5
{T_GEN_UPPEROVERLAY, SHADER_HASTOPBOTTOM}, //6
{T_GEN_LOWEROVERLAY, SHADER_HASTOPBOTTOM}, //7
{T_GEN_FULLBRIGHT, SHADER_HASFULLBRIGHT}, //8
{T_GEN_PALETTED, SHADER_HASPALETTED}, //9
{T_GEN_REFLECTCUBE, 0}, //10
{T_GEN_REFLECTMASK, 0}, //11
// {T_GEN_REFLECTION, SHADER_HASREFLECT}, //
// {T_GEN_REFRACTION, SHADER_HASREFRACT}, //
// {T_GEN_REFRACTIONDEPTH, SHADER_HASREFRACTDEPTH},//
// {T_GEN_RIPPLEMAP, SHADER_HASRIPPLEMAP}, //
//batch
{T_GEN_LIGHTMAP, SHADER_HASLIGHTMAP}, //12
{T_GEN_DELUXMAP, 0}, //13
//more lightmaps //14,15,16
//mode deluxemaps //17,18,19
};
#ifndef NOMEDIA
cin_t *cin = R_ShaderGetCinematic(shader);
#endif
//if the glsl doesn't specify all samplers, just trim them.
pass->numMergedPasses = pass->prog->numsamplers;
#ifndef NOMEDIA
if (cin && R_ShaderGetCinematic(shader) == cin)
cin = NULL;
#endif
//if the glsl has specific textures listed, be sure to provide a pass for them.
for (i = 0; i < sizeof(defaulttgen)/sizeof(defaulttgen[0]); i++)
{
if (pass->prog->defaulttextures & (1u<<i))
{
if (pass->numMergedPasses >= maxpasses)
{ //panic...
parsestate.droppass = true;
break;
}
pass[pass->numMergedPasses].flags &= ~SHADER_PASS_DEPTHCMP;
if (defaulttgen[i].gen == T_GEN_SHADOWMAP)
pass[pass->numMergedPasses].flags |= SHADER_PASS_DEPTHCMP;
#ifndef NOMEDIA
if (!i && cin)
{
pass[pass->numMergedPasses].texgen = T_GEN_VIDEOMAP;
pass[pass->numMergedPasses].cin = cin;
cin = NULL;
}
else
#endif
{
pass[pass->numMergedPasses].texgen = defaulttgen[i].gen;
#ifndef NOMEDIA
pass[pass->numMergedPasses].cin = NULL;
#endif
}
pass->numMergedPasses++;
shader->flags |= defaulttgen[i].flags;
}
}
//must have at least one texture.
if (!pass->numMergedPasses)
{
#ifndef NOMEDIA
pass[0].texgen = cin?T_GEN_VIDEOMAP:T_GEN_DIFFUSE;
pass[0].cin = cin;
#else
pass[0].texgen = T_GEN_DIFFUSE;
#endif
pass->numMergedPasses = 1;
}
#ifndef NOMEDIA
else if (cin)
Media_ShutdownCin(cin);
#endif
shader->numpasses = (pass-shader->passes)+pass->numMergedPasses;
}
void Shader_Readpass (shader_t *shader, char **ptr)
{
char *token;
shaderpass_t *pass;
qboolean ignore;
static shader_t dummy;
int conddepth = 0;
int cond[8] = {0};
unsigned int oldflags = shader->flags;
#define COND_IGNORE 1
#define COND_IGNOREPARENT 2
#define COND_ALLOWELSE 4
if ( shader->numpasses >= SHADER_PASS_MAX )
{
ignore = true;
parsestate.droppass = true;
shader = &dummy;
shader->numpasses = 1;
pass = shader->passes;
}
else
{
ignore = false;
parsestate.droppass = false;
pass = &shader->passes[shader->numpasses++];
}
// Set defaults
// Set defaults
pass->flags = 0;
pass->anim_frames[0] = r_nulltex;
pass->anim_numframes = 0;
@ -3684,8 +3894,8 @@ void Shader_Readpass (shader_t *shader, char **ptr)
pass->alphagen = ALPHA_GEN_IDENTITY;
pass->tcgen = TC_GEN_UNSPECIFIED;
pass->numtcmods = 0;
pass->numMergedPasses = 1;
pass->stagetype = ST_AMBIENT;
pass->numMergedPasses = 0;
if (shader->flags & SHADER_NOMIPMAPS)
pass->flags |= SHADER_PASS_NOMIPMAP;
@ -3749,6 +3959,10 @@ void Shader_Readpass (shader_t *shader, char **ptr)
}
}
//if there was no texgen, then its too late now.
if (!pass->numMergedPasses)
pass->numMergedPasses = 1;
if (conddepth)
{
Con_Printf("if statements without endif in shader %s\n", shader->name);
@ -3757,7 +3971,7 @@ void Shader_Readpass (shader_t *shader, char **ptr)
if (pass->tcgen == TC_GEN_UNSPECIFIED)
pass->tcgen = TC_GEN_BASE;
if (!ignore)
if (!parsestate.droppass)
{
switch(pass->stagetype)
{
@ -3770,29 +3984,24 @@ void Shader_Readpass (shader_t *shader, char **ptr)
case ST_BUMPMAP:
if (pass->texgen == T_GEN_SINGLEMAP)
shader->defaulttextures->bump = pass->anim_frames[0];
ignore = true; //fixme: scrolling etc may be important. but we're not doom3.
parsestate.droppass = true; //fixme: scrolling etc may be important. but we're not doom3.
break;
case ST_SPECULARMAP:
if (pass->texgen == T_GEN_SINGLEMAP)
shader->defaulttextures->specular = pass->anim_frames[0];
ignore = true; //fixme: scrolling etc may be important. but we're not doom3.
parsestate.droppass = true; //fixme: scrolling etc may be important. but we're not doom3.
break;
}
}
// check some things
if (ignore)
{
Shader_FreePass (pass);
shader->numpasses--;
return;
}
if ((pass->shaderbits&SBITS_BLEND_BITS) == (SBITS_SRCBLEND_ONE|SBITS_DSTBLEND_ZERO))
{
pass->shaderbits |= SBITS_MISC_DEPTHWRITE;
shader->flags |= SHADER_DEPTHWRITE;
}
if (!parsestate.droppass)
if ((pass->shaderbits&SBITS_BLEND_BITS) == (SBITS_SRCBLEND_ONE|SBITS_DSTBLEND_ZERO))
{
pass->shaderbits |= SBITS_MISC_DEPTHWRITE;
shader->flags |= SHADER_DEPTHWRITE;
}
switch (pass->rgbgen)
{
@ -3829,6 +4038,21 @@ void Shader_Readpass (shader_t *shader, char **ptr)
pass->shaderbits &= ~SBITS_MISC_DEPTHWRITE;
}
*/
//if this pass specified a program, make sure it has all the textures that the program requires
if (!parsestate.droppass && pass->prog)
Shader_FixupProgPasses(shader, pass);
if (parsestate.droppass)
{
while (pass->numMergedPasses > 0)
{
Shader_FreePass (pass+--pass->numMergedPasses);
shader->numpasses--;
}
shader->flags = oldflags;
return;
}
}
static qboolean Shader_Parsetok (shader_t *shader, shaderpass_t *pass, shaderkey_t *keys, char *token, char **ptr)
@ -3886,6 +4110,10 @@ void Shader_SetPassFlush (shaderpass_t *pass, shaderpass_t *pass2)
return;
}
//don't merge passes if they're got their own programs.
if (pass->prog || pass2->prog)
return;
/*identity alpha is required for merging*/
if (pass->alphagen != ALPHA_GEN_IDENTITY || pass2->alphagen != ALPHA_GEN_IDENTITY)
return;
@ -4423,7 +4651,7 @@ done:;
break;
pass = s->passes + i;
for (j = 1; j < s->numpasses-i && j == i + pass->numMergedPasses && j < be_maxpasses; j++)
for (j = i + pass->numMergedPasses; j < s->numpasses-i && j == i + pass->numMergedPasses && j < be_maxpasses; j++)
Shader_SetPassFlush (pass, pass + j);
i += pass->numMergedPasses;
@ -5004,7 +5232,7 @@ void Shader_DefaultBSPLM(const char *shortname, shader_t *s, const void *args)
if (!builtin && r_lightmap.ival)
builtin = (
"{\n"
"program drawflat_wall\n"
"fte_program drawflat_wall\n"
"{\n"
"map $lightmap\n"
"tcgen lightmap\n"
@ -5016,7 +5244,7 @@ void Shader_DefaultBSPLM(const char *shortname, shader_t *s, const void *args)
if (!builtin && r_drawflat.ival)
builtin = (
"{\n"
"program drawflat_wall\n"
"fte_program drawflat_wall\n"
"{\n"
"map $lightmap\n"
"tcgen lightmap\n"
@ -5026,29 +5254,34 @@ void Shader_DefaultBSPLM(const char *shortname, shader_t *s, const void *args)
);
#ifdef GLQUAKE
if (qrenderer == QR_OPENGL)
if (!builtin && r_lightprepass)
{
if (!builtin && r_lightprepass.ival)
{
builtin = (
builtin = (
"{\n"
"fte_program lpp_wall\n"
"{\n"
"map $sourcecolour\n"
"}\n"
//this is drawn during the gbuffer pass to prepare it
"fte_bemode gbuffer\n"
"{\n"
"fte_program lpp_depthnorm\n"
"{\n"
"program lpp_wall\n"
"{\n"
"map $sourcecolour\n"
"}\n"
"map $normalmap\n"
"tcgen base\n"
"}\n"
);
}
"}\n"
"}\n"
);
}
#endif
if (!builtin && ((sh_config.progs_supported && qrenderer == QR_OPENGL) || sh_config.progs_required))
{
builtin = (
"{\n"
"program defaultwall\n"
//FIXME: these maps are a legacy thing, and could be removed if third-party glsl properly contains s_diffuse
"fte_program defaultwall\n"
"{\n"
//FIXME: these maps are a legacy thing, and could be removed if third-party glsl properly contains s_diffuse
"map $diffuse\n"
"}\n"
"{\n"
@ -5111,7 +5344,7 @@ void Shader_DefaultBSPLM(const char *shortname, shader_t *s, const void *args)
Shader_DefaultScript(shortname, s, builtin);
if (r_lightprepass.ival)
if (r_lightprepass)
s->flags |= SHADER_HASNORMALMAP;
}

View File

@ -2408,7 +2408,7 @@ qboolean Sh_GenShadowMap (dlight_t *l, vec3_t axis[3], qbyte *lvis, int smsize)
}
else
{
shadowmap[isspot] = Image_CreateTexture("***shadowmap2dcube***", NULL, 0);
shadowmap[isspot] = Image_CreateTexture("***shadowmap2domni***", NULL, 0);
qglGenTextures(1, &shadowmap[isspot]->num);
GL_MTBind(0, GL_TEXTURE_2D, shadowmap[isspot]);
#ifdef DBG_COLOURNOTDEPTH
@ -2530,6 +2530,84 @@ qboolean Sh_GenShadowMap (dlight_t *l, vec3_t axis[3], qbyte *lvis, int smsize)
return true;
}
qboolean Sh_GenerateShadowMap(dlight_t *l)
{
qboolean isspot;
int smsize;
qbyte *vvis = r_refdef.scenevis;
qbyte *lvis;
/* if (Sh_ScissorForBox(mins, maxs, &rect))
{
RQuantAdd(RQUANT_RTLIGHT_CULL_SCISSOR, 1);
return;
}*/
if (vvis)
{
if (!l->rebuildcache && l->worldshadowmesh)
{
lvis = l->worldshadowmesh->litleaves;
//fixme: check head node first?
if (!Sh_LeafInView(l->worldshadowmesh->litleaves, vvis))
{
RQuantAdd(RQUANT_RTLIGHT_CULL_PVS, 1);
return false;
}
}
else
{
int clus;
clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, l->origin);
lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, lvisb, sizeof(lvisb));
//FIXME: surely we can use the phs for this?
if (!Sh_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect.
{
RQuantAdd(RQUANT_RTLIGHT_CULL_PVS, 1);
return false;
}
}
}
else
lvis = NULL;
isspot = l->fov != 0;
if (isspot)
smsize = SHADOWMAP_SIZE;
else
{
//Stolen from DP. Actually, LH pasted it to me in IRC.
vec3_t nearestpoint;
vec3_t d;
float distance, lodlinear;
nearestpoint[0] = bound(l->origin[0]-l->radius, r_origin[0], l->origin[0]+l->radius);
nearestpoint[1] = bound(l->origin[1]-l->radius, r_origin[1], l->origin[1]+l->radius);
nearestpoint[2] = bound(l->origin[2]-l->radius, r_origin[2], l->origin[2]+l->radius);
VectorSubtract(nearestpoint, r_origin, d);
distance = VectorLength(d);
lodlinear = (l->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance / l->radius));
smsize = bound(16, lodlinear, SHADOWMAP_SIZE);
}
#ifdef D3D11QUAKE
if (qrenderer == QR_DIRECT3D11)
D3D11BE_SetupForShadowMap(l, isspot, isspot?smsize:smsize*3, isspot?smsize:smsize*2, (smsize-4) / (float)SHADOWMAP_SIZE);
#endif
#ifdef VKQUAKE
if (qrenderer == QR_VULKAN)
VKBE_SetupForShadowMap(l, isspot, isspot?smsize:smsize*3, isspot?smsize:smsize*2, (smsize-4) / (float)SHADOWMAP_SIZE);
#endif
//fixme: light rotation
if (!Sh_GenShadowMap(l, l->axis, lvis, smsize))
return false; //didn't need to do anything
return true;
}
static void Sh_DrawShadowMapLight(dlight_t *l, vec3_t colour, vec3_t axis[3], qbyte *vvis)
{
vec3_t mins, maxs;
@ -3588,6 +3666,9 @@ void Sh_DrawLights(qbyte *vis)
Sh_PreGenerateLights();
}
if (r_lightprepass)
return;
if (!r_shadow_realtime_world.ival && !r_shadow_realtime_dlight.ival)
{
return;

View File

@ -6741,17 +6741,24 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_OPENGL, 110, "lpp_depthnorm",
"!!permu BUMP\n"
"!!permu SKELETAL\n"
"!!cvarf r_glsl_offsetmapping_scale\n"
//light pre-pass rendering (defered lighting)
//this is the initial pass, that draws the surface normals and depth to the initial colour buffer
"#include \"sys/defs.h\"\n"
"#if defined(OFFSETMAPPING)\n"
"varying vec3 eyevector;\n"
"#endif\n"
"varying vec3 norm, tang, bitang;\n"
"#if defined(BUMP)\n"
"varying vec2 tc;\n"
"#endif\n"
"#ifdef VERTEX_SHADER\n"
"#include \"sys/skeletal.h\"\n"
"attribute vec2 v_texcoord;\n"
"void main()\n"
"{\n"
"#if defined(BUMP)\n"
@ -6760,22 +6767,35 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"#else\n"
"gl_Position = skeletaltransform_n(norm);\n"
"#endif\n"
"#if defined(OFFSETMAPPING)\n"
"vec3 eyeminusvertex = e_eyepos - v_position.xyz;\n"
"eyevector.x = dot(eyeminusvertex, v_svector.xyz);\n"
"eyevector.y = dot(eyeminusvertex, v_tvector.xyz);\n"
"eyevector.z = dot(eyeminusvertex, v_normal.xyz);\n"
"#endif\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"#if defined(BUMP)\n"
"uniform sampler2D s_t0;\n"
"#ifdef OFFSETMAPPING\n"
"#include \"sys/offsetmapping.h\"\n"
"#endif\n"
"void main()\n"
"{\n"
//adjust texture coords for offsetmapping
"#ifdef OFFSETMAPPING\n"
"vec2 tcoffsetmap = offsetmap(s_normalmap, tc, eyevector);\n"
"#define tc tcoffsetmap\n"
"#endif\n"
"vec3 onorm;\n"
"#if defined(BUMP)\n"
"vec3 bm = 2.0*texture2D(s_t0, tc).xyz - 1.0;\n"
"vec3 bm = 2.0*texture2D(s_normalmap, tc).xyz - 1.0;\n"
"onorm = normalize(bm.x * tang + bm.y * bitang + bm.z * norm);\n"
"#else\n"
"onorm = norm;\n"
"#endif\n"
"gl_FragColor = vec4(onorm.xyz, gl_FragCoord.z / gl_FragCoord.w);\n"
"gl_FragColor = vec4(onorm.xyz, gl_FragCoord.z);\n"
"}\n"
"#endif\n"
},
@ -6787,6 +6807,9 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
//you can blame Electro for much of the maths in here.
//fixme: no fog
//s_t0 is the normals and depth
//output should be amount of light hitting the surface.
"varying vec4 tf;\n"
"#ifdef VERTEX_SHADER\n"
"void main()\n"
@ -6796,27 +6819,147 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0;\n"
"uniform sampler2D s_t0; //norm.xyz, depth\n"
"uniform vec3 l_lightposition;\n"
"uniform mat4 m_invviewprojection;\n"
"uniform vec3 l_lightcolour;\n"
"uniform float l_lightradius;\n"
"uniform mat4 l_cubematrix;\n"
"#ifdef PCF\n"
"#define USE_ARB_SHADOW\n"
"#ifndef USE_ARB_SHADOW\n"
//fall back on regular samplers if we must
"#define sampler2DShadow sampler2D\n"
"#endif\n"
"uniform sampler2DShadow s_shadowmap;\n"
"uniform vec4 l_shadowmapproj; //light projection matrix info\n"
"uniform vec2 l_shadowmapscale; //xy are the texture scale, z is 1, w is the scale.\n"
"vec3 ShadowmapCoord(vec4 cubeproj)\n"
"{\n"
"#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"
//#elif defined(CUBESHADOW)
// vec3 shadowcoord = vshadowcoord.xyz / vshadowcoord.w;
// #define dosamp(x,y) shadowCube(s_shadowmap, shadowcoord + vec2(x,y)*texscale.xy).r
"#else\n"
//figure out which axis to use
//texture is arranged thusly:
//forward left up
//back right down
"vec3 dir = abs(cubeproj.xyz);\n"
//assume z is the major axis (ie: forward from the light)
"vec3 t = cubeproj.xyz;\n"
"float ma = dir.z;\n"
"vec3 axis = vec3(0.5/3.0, 0.5/2.0, 0.5);\n"
"if (dir.x > ma)\n"
"{\n"
"ma = dir.x;\n"
"t = cubeproj.zyx;\n"
"axis.x = 0.5;\n"
"}\n"
"if (dir.y > ma)\n"
"{\n"
"ma = dir.y;\n"
"t = cubeproj.xzy;\n"
"axis.x = 2.5/3.0;\n"
"}\n"
//if the axis is negative, flip it.
"if (t.z > 0.0)\n"
"{\n"
"axis.y = 1.5/2.0;\n"
"t.z = -t.z;\n"
"}\n"
//we also need to pass the result through the light's projection matrix too
//the 'matrix' we need only contains 5 actual values. and one of them is a -1. So we might as well just use a vec4.
//note: the projection matrix also includes scalers to pinch the image inwards to avoid sampling over borders, as well as to cope with non-square source image
//the resulting z is prescaled to result in a value between -0.5 and 0.5.
//also make sure we're in the right quadrant type thing
"return axis + ((l_shadowmapproj.xyz*t.xyz + vec3(0.0, 0.0, l_shadowmapproj.w)) / -t.z);\n"
"#endif\n"
"}\n"
"float ShadowmapFilter(vec4 vtexprojcoord)\n"
"{\n"
"vec3 shadowcoord = ShadowmapCoord(vtexprojcoord);\n"
"#if 0//def GL_ARB_texture_gather\n"
"vec2 ipart, fpart;\n"
"#define dosamp(x,y) textureGatherOffset(s_shadowmap, ipart.xy, vec2(x,y)))\n"
"vec4 tl = step(shadowcoord.z, dosamp(-1.0, -1.0));\n"
"vec4 bl = step(shadowcoord.z, dosamp(-1.0, 1.0));\n"
"vec4 tr = step(shadowcoord.z, dosamp(1.0, -1.0));\n"
"vec4 br = step(shadowcoord.z, dosamp(1.0, 1.0));\n"
//we now have 4*4 results, woo
//we can just average them for 1/16th precision, but that's still limited graduations
//the middle four pixels are 'full strength', but we interpolate the sides to effectively give 3*3
"vec4 col = vec4(tl.ba, tr.ba) + vec4(bl.rg, br.rg) + //middle two rows are full strength\n"
"mix(vec4(tl.rg, tr.rg), vec4(bl.ba, br.ba), fpart.y); //top+bottom rows\n"
"return dot(mix(col.rgb, col.agb, fpart.x), vec3(1.0/9.0)); //blend r+a, gb are mixed because its pretty much free and gives a nicer dot instruction instead of lots of adds.\n"
"#else\n"
"#ifdef USE_ARB_SHADOW\n"
//with arb_shadow, we can benefit from hardware acclerated pcf, for smoother shadows
"#define dosamp(x,y) shadow2D(s_shadowmap, shadowcoord.xyz + (vec3(x,y,0.0)*l_shadowmapscale.xyx)).r\n"
"#else\n"
//this will probably be a bit blocky.
"#define dosamp(x,y) float(texture2D(s_shadowmap, shadowcoord.xy + (vec2(x,y)*l_shadowmapscale.xy)).r >= shadowcoord.z)\n"
"#endif\n"
"float s = 0.0;\n"
"#if r_glsl_pcf >= 1 && r_glsl_pcf < 5\n"
"s += dosamp(0.0, 0.0);\n"
"return s;\n"
"#elif r_glsl_pcf >= 5 && r_glsl_pcf < 9\n"
"s += dosamp(-1.0, 0.0);\n"
"s += dosamp(0.0, -1.0);\n"
"s += dosamp(0.0, 0.0);\n"
"s += dosamp(0.0, 1.0);\n"
"s += dosamp(1.0, 0.0);\n"
"return s/5.0;\n"
"#else\n"
"s += dosamp(-1.0, -1.0);\n"
"s += dosamp(-1.0, 0.0);\n"
"s += dosamp(-1.0, 1.0);\n"
"s += dosamp(0.0, -1.0);\n"
"s += dosamp(0.0, 0.0);\n"
"s += dosamp(0.0, 1.0);\n"
"s += dosamp(1.0, -1.0);\n"
"s += dosamp(1.0, 0.0);\n"
"s += dosamp(1.0, 1.0);\n"
"return s/9.0;\n"
"#endif\n"
"#endif\n"
"}\n"
"#else\n"
"float ShadowmapFilter(vec4 vtexprojcoord)\n"
"{\n"
"return 1.0;\n"
"}\n"
"#endif\n"
"vec3 calcLightWorldPos(vec2 screenPos, float depth)\n"
"{\n"
"vec4 pos;\n"
"pos.x = screenPos.x;\n"
"pos.y = screenPos.y;\n"
"pos.z = depth;\n"
"pos.w = 1.0;\n"
"pos = m_invviewprojection * pos;\n"
"vec4 pos = m_invviewprojection * vec4(screenPos.xy, (depth*2.0)-1.0, 1.0);\n"
"return pos.xyz / pos.w;\n"
"}\n"
"void main ()\n"
"{\n"
"vec3 lightColour = l_lightcolour.rgb;\n"
"float lightIntensity = 1.0;\n"
"float lightIntensity = 1.0;\n"
"float lightAttenuation = l_lightradius; // fixme: just use the light radius for now, use better near/far att math separately once working\n"
"float radiusFar = l_lightradius;\n"
"float radiusFar = l_lightradius;\n"
"float radiusNear = l_lightradius*0.5;\n"
"vec2 fc;\n"
@ -6828,54 +6971,86 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
/* calc where the wall that generated this sample came from */
"vec3 worldPos = calcLightWorldPos(fc, depth);\n"
/*we need to know the cube projection (for both cubemaps+shadows)*/
"vec4 cubeaxis = l_cubematrix*vec4(worldPos.xyz, 1.0);\n"
/*calc diffuse lighting term*/
"vec3 lightDir = l_lightposition - worldPos;\n"
"float zdiff = 1.0 - clamp(length(lightDir) / lightAttenuation, 0.0, 1.0);\n"
"float atten = (radiusFar * zdiff) / (radiusFar - radiusNear);\n"
"atten = pow(atten, 2.0);\n"
"lightDir = normalize(lightDir);\n"
"float nDotL = dot(norm, lightDir) * atten;\n"
"float lightDiffuse = max(0.0, nDotL);\n"
"float nDotL = dot(norm, lightDir);\n"
"float lightDiffuse = max(0.0, nDotL) * atten;\n"
"gl_FragColor = vec4(lightDiffuse * (lightColour * lightIntensity), 1.0);\n"
//fixme: apply fog
//fixme: output a specular term
//fixme: cubemap filters
"gl_FragColor = vec4(lightDiffuse * (lightColour * lightIntensity) * ShadowmapFilter(cubeaxis), 1.0);\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "lpp_wall",
"!!permu BUMP //for offsetmapping rather than bumpmapping (real bumps are handled elsewhere)\n"
"!!cvarf r_glsl_offsetmapping_scale\n"
//the final defered lighting pass.
//the lighting values were written to some render target, which is fed into this shader, and now we draw all the wall textures with it.
"#include \"sys/defs.h\"\n"
"#if defined(OFFSETMAPPING)\n"
"varying vec3 eyevector;\n"
"#endif\n"
"varying vec2 tc, lm;\n"
"varying vec4 tf;\n"
"#ifdef VERTEX_SHADER\n"
"attribute vec2 v_texcoord;\n"
"attribute vec2 v_lmcoord;\n"
"void main ()\n"
"{\n"
"tc = v_texcoord;\n"
"lm = v_lmcoord;\n"
"gl_Position = tf = ftetransform();\n"
"#if defined(OFFSETMAPPING)\n"
"vec3 eyeminusvertex = e_eyepos - v_position.xyz;\n"
"eyevector.x = dot(eyeminusvertex, v_svector.xyz);\n"
"eyevector.y = dot(eyeminusvertex, v_tvector.xyz);\n"
"eyevector.z = dot(eyeminusvertex, v_normal.xyz);\n"
"#endif\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0;\n"
"uniform sampler2D s_t1;\n"
"uniform sampler2D s_t2;\n"
"uniform vec4 e_lmscale;\n"
"uniform sampler2D s_t0; //light gbuffer\n"
"#ifdef OFFSETMAPPING\n"
"#include \"sys/offsetmapping.h\"\n"
"#endif\n"
"void main ()\n"
"{\n"
//adjust texture coords for offsetmapping
"#ifdef OFFSETMAPPING\n"
"vec2 tcoffsetmap = offsetmap(s_normalmap, tc, eyevector);\n"
"#define tc tcoffsetmap\n"
"#endif\n"
"vec2 nst;\n"
"nst = tf.xy / tf.w;\n"
"nst = (1.0 + nst) / 2.0;\n"
"vec4 l = texture2D(s_t0, nst)*5.0;\n"
"vec4 c = texture2D(s_t1, tc);\n"
"vec3 lmsamp = texture2D(s_t2, lm).rgb*e_lmscale.rgb;\n"
"vec4 l = texture2D(s_t0, nst);\n"
"vec4 c = texture2D(s_diffuse, tc);\n"
//fixme: top+bottom should add upper+lower colours to c here
"vec3 lmsamp = texture2D(s_lightmap, lm).rgb*e_lmscale.rgb;\n"
//fixme: fog the legacy lightmap data
"vec3 diff = l.rgb;\n"
"vec3 chrom = diff / (0.001 + dot(diff, vec3(0.3, 0.59, 0.11)));\n"
"vec3 spec = chrom * l.a;\n"
// vec3 chrom = diff / (0.001 + dot(diff, vec3(0.3, 0.59, 0.11)));
// vec3 spec = chrom * l.a;
//fixme: do specular somehow
"gl_FragColor = vec4((diff + lmsamp) * c.xyz, 1.0);\n"
//fixme: fullbrights should add to the rgb value
"}\n"
"#endif\n"
},

View File

@ -172,6 +172,8 @@ enum
typedef struct shaderpass_s {
int numMergedPasses;
struct programshared_s *prog;
#ifndef NOMEDIA
struct cin_s *cin;
#endif
@ -511,7 +513,7 @@ enum
bemoverride_crepuscular = LSHADER_MODES, //either black (non-sky) or a special crepuscular_sky shader
bemoverride_depthonly, //depth masked. replace if you want alpha test.
bemoverride_depthdark, //itself or a pure-black shader. replace for alpha test.
bemoverride_prelight, //prelighting
bemoverride_gbuffer, //prelighting
bemoverride_fog, //post-render volumetric fog
bemoverride_max
};
@ -741,7 +743,7 @@ batch_t *GLBE_GetTempBatch(void);
void GLBE_GenBrushModelVBO(model_t *mod);
void GLBE_ClearVBO(vbo_t *vbo);
void GLBE_UploadAllLightmaps(void);
void GLBE_DrawWorld (batch_t **worldbatches, qbyte *vis);
void GLBE_DrawWorld (batch_t **worldbatches);
qboolean GLBE_LightCullModel(vec3_t org, model_t *model);
void GLBE_SelectEntity(entity_t *ent);
qboolean GLBE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsigned int lmode);
@ -771,7 +773,7 @@ batch_t *D3D9BE_GetTempBatch(void);
void D3D9BE_GenBrushModelVBO(model_t *mod);
void D3D9BE_ClearVBO(vbo_t *vbo);
void D3D9BE_UploadAllLightmaps(void);
void D3D9BE_DrawWorld (batch_t **worldbatches, qbyte *vis);
void D3D9BE_DrawWorld (batch_t **worldbatches);
qboolean D3D9BE_LightCullModel(vec3_t org, model_t *model);
void D3D9BE_SelectEntity(entity_t *ent);
qboolean D3D9BE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsigned int lmode);
@ -795,7 +797,7 @@ batch_t *D3D11BE_GetTempBatch(void);
void D3D11BE_GenBrushModelVBO(model_t *mod);
void D3D11BE_ClearVBO(vbo_t *vbo);
void D3D11BE_UploadAllLightmaps(void);
void D3D11BE_DrawWorld (batch_t **worldbatches, qbyte *vis);
void D3D11BE_DrawWorld (batch_t **worldbatches);
qboolean D3D11BE_LightCullModel(vec3_t org, model_t *model);
void D3D11BE_SelectEntity(entity_t *ent);
qboolean D3D11BE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsigned int lmode);

View File

@ -25,6 +25,7 @@ ifneq ($(DEBUG),)
else
BASE_LDFLAGS+=-s
endif
BASE_LDFLAGS+=-lz
# set to "" for debugging
DO_CC?=$(CC) $(BASE_CFLAGS) -o $@ -c $< $(CFLAGS)
@ -46,7 +47,7 @@ win:
$(MAKE) USEGUI_CFLAGS="-DUSEGUI -DQCCONLY" R_win
R_qcc: $(QCC_OBJS) $(COMMON_OBJS) $(TUI_OBJS)
$(CC) $(BASE_CFLAGS) -o fteqcc.bin -O3 $(BASE_LDFLAGS) $(QCC_OBJS) $(TUI_OBJS) $(COMMON_OBJS)
$(CC) $(BASE_CFLAGS) -o fteqcc.bin -O3 $(BASE_LDFLAGS) -lm $(QCC_OBJS) $(TUI_OBJS) $(COMMON_OBJS)
qcc:
$(MAKE) USEGUI_CFLAGS="" R_qcc

View File

@ -1,3 +1,12 @@
#if _MSC_VER >= 1300
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#ifndef _CRT_NONSTDC_NO_WARNINGS
#define _CRT_NONSTDC_NO_WARNINGS
#endif
#endif
#include "hash.h"
#include <stdlib.h>
#include <string.h>

View File

@ -1055,6 +1055,7 @@ typedef struct qcc_cachedsourcefile_s {
struct qcc_cachedsourcefile_s *next;
} qcc_cachedsourcefile_t;
extern qcc_cachedsourcefile_t *qcc_sourcefile;
int WriteSourceFiles(qcc_cachedsourcefile_t *filelist, int h, pbool sourceaswell, pbool legacyembed);

View File

@ -2287,17 +2287,20 @@ void QCC_PR_LexWhitespace (pbool inhibitpreprocessor)
#define MAX_FRAMES 8192
char pr_framemodelname[64];
char pr_framemacros[MAX_FRAMES][64];
int pr_framemacrovalue[MAX_FRAMES];
int pr_nummacros, pr_oldmacros;
int pr_macrovalue;
int pr_savedmacro;
struct
{
char name[64];
int value;
const char *file; //compare to s_filen to see if its current or not
} pr_framemacro[MAX_FRAMES];
int pr_nummacros;
int pr_macrovalue; //next value to use
int pr_savedmacro; //for sub-groups.
void QCC_PR_ClearGrabMacros (pbool newfile)
{
if (!newfile)
pr_nummacros = 0;
pr_oldmacros = pr_nummacros;
pr_macrovalue = 0;
pr_savedmacro = -1;
}
@ -2308,17 +2311,21 @@ int QCC_PR_FindMacro (char *name)
for (i=pr_nummacros-1 ; i>=0 ; i--)
{
if (!STRCMP (name, pr_framemacros[i]))
if (!STRCMP (name, pr_framemacro[i].name))
{
return pr_framemacrovalue[i];
if (pr_framemacro[i].file != s_filen)
QCC_PR_ParseWarning(WARN_DUPLICATEMACRO, "Stale macro used (%s, defined in %s)", pr_token, pr_framemacro[i].file);
return pr_framemacro[i].value;
}
}
for (i=pr_nummacros-1 ; i>=0 ; i--)
{
if (!stricmp (name, pr_framemacros[i]))
if (!stricmp (name, pr_framemacro[i].name))
{
QCC_PR_ParseWarning(WARN_CASEINSENSITIVEFRAMEMACRO, "Case insensitive frame macro");
return pr_framemacrovalue[i];
QCC_PR_ParseWarning(WARN_CASEINSENSITIVEFRAMEMACRO, "Case insensitive frame macro (using %s)", pr_framemacro[i].name);
if (pr_framemacro[i].file != s_filen)
QCC_PR_ParseWarning(WARN_DUPLICATEMACRO, "Stale macro used (%s, defined in %s)", pr_token, pr_framemacro[i].file);
return pr_framemacro[i].value;
}
}
return -1;
@ -2497,27 +2504,34 @@ pbool QCC_PR_LexMacroName(void)
return i!=0;
}
void QCC_PR_MacroFrame(char *name, int value)
void QCC_PR_MacroFrame(char *name, int value, pbool force)
{
int i;
for (i=pr_nummacros-1 ; i>=0 ; i--)
{
if (!STRCMP (name, pr_framemacros[i]))
if (!STRCMP (name, pr_framemacro[i].name))
{
pr_framemacrovalue[i] = value;
if (i>=pr_oldmacros)
//vanilla macro behaviour is to not realise that there's dupes. lookups find the first, so dupes end up as dead gaps.
//our caller incremented the value externally
//so warn+ignore if its from the same file
if (pr_framemacro[i].file == s_filen && !force)
QCC_PR_ParseWarning(WARN_DUPLICATEMACRO, "Duplicate macro defined (%s)", pr_token);
//else it's from an old file, and shouldn't be mentioned.
else
{
pr_framemacro[i].value = value; //old file, override it, whatever the old value was is redundant now
pr_framemacro[i].file = s_filen;
}
return;
}
}
if (strlen(name)+1 > sizeof(pr_framemacros[0]))
if (strlen(name)+1 > sizeof(pr_framemacro[0].name))
QCC_PR_ParseWarning(ERR_TOOMANYFRAMEMACROS, "Name for frame macro %s is too long", name);
else
{
strcpy (pr_framemacros[pr_nummacros], name);
pr_framemacrovalue[pr_nummacros] = value;
strcpy (pr_framemacro[pr_nummacros].name, name);
pr_framemacro[pr_nummacros].value = value;
pr_framemacro[pr_nummacros].file = s_filen;
pr_nummacros++;
if (pr_nummacros >= MAX_FRAMES)
QCC_PR_ParseError(ERR_TOOMANYFRAMEMACROS, "Too many frame macros defined");
@ -2528,7 +2542,7 @@ void QCC_PR_ParseFrame (void)
{
while (QCC_PR_LexMacroName ())
{
QCC_PR_MacroFrame(pr_token, pr_macrovalue++);
QCC_PR_MacroFrame(pr_token, pr_macrovalue++, false);
}
}
@ -2596,7 +2610,7 @@ void QCC_PR_LexGrab (void)
QCC_PR_LexMacroName ();
if (*pr_framemodelname)
QCC_PR_MacroFrame(pr_framemodelname, pr_macrovalue);
QCC_PR_MacroFrame(pr_framemodelname, pr_macrovalue, true);
QC_strlcpy(pr_framemodelname, pr_token, sizeof(pr_framemodelname));

File diff suppressed because it is too large Load Diff

View File

@ -674,7 +674,7 @@ void QCC_PrintFiles (void)
}
int encode(int len, int method, char *in, int handle);
int WriteSourceFiles(int h, pbool sourceaswell, pbool legacyembed)
int WriteSourceFiles(qcc_cachedsourcefile_t *filelist, int h, pbool sourceaswell, pbool legacyembed)
{
//helpers to deal with misaligned data. writes little-endian.
#define misbyte(ptr,ofs,data) ((unsigned char*)(ptr))[ofs] = (data)&0xff;
@ -688,7 +688,7 @@ int WriteSourceFiles(int h, pbool sourceaswell, pbool legacyembed)
int startofs;
sourceaswell |= flag_embedsrc;
for (f = qcc_sourcefile,num=0; f ; f=f->next)
for (f = filelist,num=0; f ; f=f->next)
{
if (f->type == FT_CODE && !sourceaswell)
continue;
@ -714,7 +714,7 @@ int WriteSourceFiles(int h, pbool sourceaswell, pbool legacyembed)
}
startofs = SafeSeek(h, 0, SEEK_CUR);
idf = qccHunkAlloc(sizeof(includeddatafile_t)*num);
for (f = qcc_sourcefile,num=0; f ; f=f->next)
for (f = filelist,num=0; f ; f=f->next)
{
if (f->type == FT_CODE && !sourceaswell)
continue;
@ -783,7 +783,7 @@ int WriteSourceFiles(int h, pbool sourceaswell, pbool legacyembed)
char centralheader[46+sizeof(f->filename)];
int centraldirsize;
ofs = SafeSeek(h, 0, SEEK_CUR);
for (f = qcc_sourcefile,num=0; f ; f=f->next)
for (f = filelist,num=0; f ; f=f->next)
{
size_t fnamelen;
if (f->type == FT_CODE && !sourceaswell)
@ -833,8 +833,6 @@ int WriteSourceFiles(int h, pbool sourceaswell, pbool legacyembed)
else
ofs = 0;
qcc_sourcefile = NULL;
printf("Embedded files take %u bytes\n", SafeSeek(h, 0, SEEK_CUR) - startofs);
return ofs;
@ -2081,17 +2079,17 @@ strofs = (strofs+3)&~3;
{
case QCF_QTEST:
progs.version = PROG_QTESTVERSION;
progs.ofsfiles = WriteSourceFiles(h, debugtarget, false);
progs.ofsfiles = WriteSourceFiles(qcc_sourcefile, h, debugtarget, false);
break;
case QCF_KK7:
progs.version = PROG_KKQWSVVERSION;
progs.ofsfiles = WriteSourceFiles(h, debugtarget, false);
progs.ofsfiles = WriteSourceFiles(qcc_sourcefile, h, debugtarget, false);
break;
default:
case QCF_STANDARD:
case QCF_HEXEN2: //urgh
progs.version = PROG_VERSION;
progs.ofsfiles = WriteSourceFiles(h, debugtarget, false);
progs.ofsfiles = WriteSourceFiles(qcc_sourcefile, h, debugtarget, false);
break;
case QCF_DARKPLACES:
case QCF_FTE:
@ -2147,9 +2145,10 @@ strofs = (strofs+3)&~3;
progs.numtypes = 0;
}
progs.ofsfiles = WriteSourceFiles(h, debugtarget, true);
progs.ofsfiles = WriteSourceFiles(qcc_sourcefile, h, debugtarget, true);
break;
}
qcc_sourcefile = NULL;
if (progs.version != PROG_EXTENDEDVERSION && progs.numbodylessfuncs)
printf ("WARNING: progs format cannot handle extern functions\n");

View File

@ -211,7 +211,18 @@ pbool QC_EnumerateFilesFromBlob(const void *blob, size_t blobsize, void (*cb)(co
el = QC_ReadRawShort(cd+30);
cl = QC_ReadRawShort(cd+32);
if (QC_ReadRawShort(cd+8) != 0)
//1=encrypted
//2,4=encoder flags
//8=crc etc info is dodgy
//10=enhanced deflate
//20=patchdata
//40=strong encryption
//80,100,200,400=unused
//800=utf-8
//1000=enh comp
//2000=masked localheader
//4000,8000=reserved
if (QC_ReadRawShort(cd+8) & ~0x80e)
continue;
{
@ -221,7 +232,7 @@ pbool QC_EnumerateFilesFromBlob(const void *blob, size_t blobsize, void (*cb)(co
if (QC_ReadRawInt(le+0) != 0x04034b50)
continue;
if (QC_ReadRawShort(le+6) != 0) //general purpose flags
if (QC_ReadRawShort(le+6) & ~0x80e) //general purpose flags
continue;
method = QC_ReadRawShort(le+8);
if (method != 0 && method != 8)

View File

@ -10059,7 +10059,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"findfloat", PF_FindFloat, 0, 0, 0, 98, D("#define findentity findfloat\nentity(entity start, .__variant fld, __variant match)", "Equivelent to the find builtin, but instead of comparing strings contents, this builtin compares the raw values. This builtin requires multiple calls in order to scan all entities - set start to the previous call's return value.\nworld is returned when there are no more entities.")}, // #98 (DP_QC_FINDFLOAT)
{"checkextension", PF_checkextension, 99, 99, 0, 99, D("float(string extname)", "Checks for an extension by its name (eg: checkextension(\"FRIK_FILE\") says that its okay to go ahead and use strcat).\nUse cvar(\"pr_checkextension\") to see if this builtin exists.")}, // #99 //darkplaces system - query a string to see if the mod supports X Y and Z.
{"checkbuiltin", PF_checkbuiltin, 0, 0, 0, 0, D("float(__variant funcref)", "Checks to see if the specified builtin is supported/mapped. This is intended as a way to check for #0 functions, allowing for simple single-builtin functions.")},
{"checkbuiltin", PF_checkbuiltin, 0, 0, 0, 0, D("float(__variant funcref)", "Checks to see if the specified builtin is supported/mapped. This is intended as a way to check for #0 functions, allowing for simple single-builtin functions. Warning, if two different engines map different builtins to the same number, then this function will not tell you which will be called, only that it won't crash (the exception being #0, which are remapped as available).")},
{"builtin_find", PF_builtinsupported,100, 100, 0, 100, D("float(string builtinname)", "Looks to see if the named builtin is valid, and returns the builtin number it exists at.")}, // #100 //per builtin system.
{"anglemod", PF_anglemod, 0, 0, 0, 102, "float(float value)"},
{"qsg_cvar_string", PF_cvar_string, 0, 0, 0, 103, D("string(string cvarname)","An old/legacy equivelent of more recent/common builtins in order to read a cvar's string value."), true},

View File

@ -1630,6 +1630,12 @@ static void SV_StuffToClient_f(void)
char *c;
char *key;
if (Cmd_Argc() < 3)
{
Con_Printf("%s <clientname> <consolecommand>\n", Cmd_Argv(0));
return;
}
Cmd_ShiftArgs(1, Cmd_ExecLevel==RESTRICT_LOCAL);
if (!strcmp(Cmd_Argv(1), "bind"))
{

View File

@ -77,6 +77,7 @@ cvar_t allow_download = CVARD("allow_download", "1", "If 1, permits downloadi
cvar_t allow_download_skins = CVARD("allow_download_skins", "1", "0 blocks downloading of any file in the skins/ directory");
cvar_t allow_download_models = CVARD("allow_download_models", "1", "0 blocks downloading of any file in the progs/ or models/ directory");
cvar_t allow_download_sounds = CVARD("allow_download_sounds", "1", "0 blocks downloading of any file in the sound/ directory");
cvar_t allow_download_particles = CVARD("allow_download_particles", "1", "0 blocks downloading of any file in the particles/ directory");
cvar_t allow_download_demos = CVARD("allow_download_demos", "1", "0 blocks downloading of any file in the demos/ directory");
cvar_t allow_download_maps = CVARD("allow_download_maps", "1", "0 blocks downloading of any file in the maps/ directory");
cvar_t allow_download_logs = CVARD("allow_download_logs", "0", "1 permits downloading files with the extension .log\n"CON_ERROR"THIS IS DANGEROUS AS IT POTENTIALLY ALLOWS PEOPLE TO SEE PASSWORDS OR OTHER PRIVATE INFORMATION.\nNote that it can be switch on/off via rcon.");
@ -87,7 +88,7 @@ cvar_t allow_download_textures = CVARD("allow_download_textures", "1", "0 block
cvar_t allow_download_packages = CVARD("allow_download_packages", "1", "if 1, permits downloading files (from root directory or elsewhere) with known package extensions (eg: pak+pk3). Packages with a name starting 'pak' are covered by allow_download_copyrighted as well. This does not prevent ");
cvar_t allow_download_refpackages = CVARD("allow_download_refpackages", "1", "If set to 1, packages that contain files needed during spawn functions will be become 'referenced' and automatically downloaded to clients.\nThis cvar should probably not be set if you have large packages that provide replacement pickup models on public servers.\nThe path command will show a '(ref)' tag next to packages which clients will automatically attempt to download.");
cvar_t allow_download_wads = CVARD("allow_download_wads", "1", "0 blocks downloading of any file in the wads/ directory, or is in the root directory with the extension .wad");
cvar_t allow_download_configs = CVARD("allow_download_configs", "0", "1 allows downloading of config files, either with the extension .cfg or in the subdir configs/.\n"CON_ERROR"THIS IS DANGEROUS AS IT CAN ALLOW PEOPLE TO READ YOUR RCON PASSWORD.");
cvar_t allow_download_configs = CVARD("allow_download_configs", "0", "1 allows downloading of config files, either with the extension .cfg or in the subdir configs/.\n"CON_ERROR"THIS IS DANGEROUS AS IT CAN ALLOW PEOPLE TO READ YOUR RCON PASSWORD ETC.");
cvar_t allow_download_locs = CVARD("allow_download_locs", "1", "0 blocks downloading of any file in the locs/ directory");
cvar_t allow_download_copyrighted = CVARD("allow_download_copyrighted", "0", "0 blocks download of packages that are considered copyrighted. Specifically, this means packages with a leading 'pak' prefix on the filename.\nIf you take your copyrights seriously, you should also set allow_download_pakmaps 0 and allow_download_pakcontents 0.");
cvar_t allow_download_other = CVARD("allow_download_other", "0", "0 blocks downloading of any file that was not covered by any of the directory download blocks.");

View File

@ -2767,6 +2767,7 @@ qboolean SV_AllowDownload (const char *name)
extern cvar_t allow_download_skins;
extern cvar_t allow_download_models;
extern cvar_t allow_download_sounds;
extern cvar_t allow_download_particles;
extern cvar_t allow_download_demos;
extern cvar_t allow_download_maps;
extern cvar_t allow_download_textures;
@ -2800,7 +2801,7 @@ qboolean SV_AllowDownload (const char *name)
return false;
if (*name == '/') //no absolute.
return false;
if (strchr(name, '\\')) //no windows paths - grow up lame windows users.
if (strchr(name, '\\')) //no windows paths - grow up you lame windows users.
return false;
COM_FileExtension(name, ext, sizeof(ext));
@ -2813,6 +2814,7 @@ qboolean SV_AllowDownload (const char *name)
if (!strncmp(name, "package/", 8))
{
//eg: package/id1/foobar.pk3
if (!strcmp("pk4", ext) || !strcmp("pk3", ext) || !strcmp("pak", ext) || (!strncmp(name, "package/downloads/", 18) && !strcmp("zip", ext)))
{
if (!allow_download_packages.ival)
@ -2839,6 +2841,9 @@ qboolean SV_AllowDownload (const char *name)
//sound
if (strncmp(name, "sound/", 6) == 0)
return !!allow_download_sounds.value;
//particles
if (strncmp(name, "particles/", 6) == 0)
return !!allow_download_particles.value;
//demos
if (strncmp(name, "demos/", 6) == 0)
return !!allow_download_demos.value;
@ -2847,9 +2852,6 @@ qboolean SV_AllowDownload (const char *name)
if (strncmp(name, "textures/", 9) == 0)
return !!allow_download_textures.value;
if (strncmp(name, "config/", 7) == 0)
return !!allow_download_configs.value;
if (strncmp(name, "locs/", 5) == 0)
return !!allow_download_locs.value;
@ -2859,8 +2861,14 @@ qboolean SV_AllowDownload (const char *name)
if (!strchr(name, '/') && !strcmp("wad", ext))
return !!allow_download_wads.value;
//configs
if (strncmp(name, "config/", 7) == 0)
return !!allow_download_configs.value;
if (!strcmp("cfg", ext))
return !!allow_download_configs.value;
//pak/pk3s.
if (!strcmp("pk4", ext) || !strcmp("pk3", ext) || !strcmp("pak", ext))
if (!strchr(name, '/') && (!strcmp("pk4", ext) || !strcmp("pk3", ext) || !strcmp("pak", ext)))
{
if (strnicmp(name, "pak", 3)) //don't give out core pak/pk3 files. This matches q3 logic.
return !!allow_download_packages.value;
@ -2868,9 +2876,6 @@ qboolean SV_AllowDownload (const char *name)
return !!allow_download_packages.value && !!allow_download_copyrighted.value;
}
if (!strcmp("cfg", ext))
return !!allow_download_configs.value;
//root of gamedir
if (!strchr(name, '/') && !allow_download_root.value)
{
@ -2960,9 +2965,9 @@ static int SV_LocateDownload(char *name, flocation_t *loc, char **replacementnam
static const char *alternatives[][4] = {
//orig-path, orig-ext, new-path, new-ext
//nexuiz qc names [sound/]sound/foo.wav but expects sound/foo.ogg and variations of that (the [sound/] is implied, but ignored)
{"", "", ".wav", ".ogg"},//nexuiz qc names .wav, but the paks use .ogg
{"", "", ".wav", ".ogg"}, //nexuiz qc names .wav, but the paks use .ogg
{"sound/", "", ".wav", ".wav"}, //nexuiz qc names sound/ but that's normally implied, resulting in doubles that don't exist in the filesystem
{"sound/", "", ".wav", ".ogg"} //both of nexuiz's issues
{"sound/", "", ".wav", ".ogg"} //both of nexuiz's issues at the same time
};
for (alt = 0; alt < countof(alternatives); alt++)

View File

@ -167,7 +167,7 @@ void SWBE_DrawMesh_List(shader_t *shader, int nummeshes, struct mesh_s **mesh, s
void SWBE_DrawMesh_Single(shader_t *shader, struct mesh_s *meshchain, struct vbo_s *vbo, unsigned int be_flags);
void SWBE_SubmitBatch(struct batch_s *batch);
struct batch_s *SWBE_GetTempBatch(void);
void SWBE_DrawWorld(batch_t **worldbatches, qbyte *vis);
void SWBE_DrawWorld(batch_t **worldbatches);
void SWBE_Init(void);
void SWBE_GenBrushModelVBO(struct model_s *mod);
void SWBE_ClearVBO(struct vbo_s *vbo);

View File

@ -610,7 +610,7 @@ void SWBE_Set2D(void)
SWBE_UpdateUniforms();
}
void SWBE_DrawWorld(batch_t **worldbatches, qbyte *vis)
void SWBE_DrawWorld(batch_t **worldbatches)
{
batch_t *batches[SHADER_SORT_COUNT];

View File

@ -5,6 +5,8 @@
#include "gl_draw.h"
#include "shader.h"
//FIXME: instead of switching rendertargets and back, we should be using an alternative queue.
#define PERMUTATION_BEM_DEPTHONLY (1u<<14)
#define PERMUTATION_BEM_WIREFRAME (1u<<15)
@ -1433,8 +1435,8 @@ static void *fte_restrict VKBE_AllocateBufferSpace(enum dynbuf_e type, size_t da
{
//flush the old one, just in case.
VkMappedMemoryRange range = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE};
range.offset = 0;
range.size = b->offset;
range.offset = b->flushed;
range.size = b->offset-b->flushed;
range.memory = b->stagingmemory;
vkFlushMappedMemoryRanges(vk.device, 1, &range);
@ -1442,9 +1444,9 @@ static void *fte_restrict VKBE_AllocateBufferSpace(enum dynbuf_e type, size_t da
{
struct vk_fencework *fence = VK_FencedBegin(NULL, 0);
VkBufferCopy bcr = {0};
bcr.srcOffset = 0;
bcr.dstOffset = 0;
bcr.size = b->offset;
bcr.srcOffset = b->flushed;
bcr.dstOffset = b->flushed;
bcr.size = b->offset-b->flushed;
vkCmdCopyBuffer(fence->cbuf, b->stagingbuf, b->devicebuf, 1, &bcr);
VK_FencedSubmit(fence);
}
@ -1453,6 +1455,7 @@ static void *fte_restrict VKBE_AllocateBufferSpace(enum dynbuf_e type, size_t da
VKBE_AllocNewBuffer(&b->next, type);
b = vk.dynbuf[type] = b->next;
b->offset = 0;
b->flushed = 0;
}
*buf = b->renderbuf;
@ -1499,28 +1502,29 @@ void VKBE_FlushDynamicBuffers(void)
uint32_t i;
struct dynbuffer *d;
VkMappedMemoryRange range = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE};
range.offset = 0;
for (i = 0; i < DB_MAX; i++)
{
d = vk.dynbuf[i];
if (!d->offset)
if (d->flushed == d->offset)
continue;
range.size = d->offset;
range.offset = d->flushed;
range.size = d->offset - d->flushed;
range.memory = d->stagingmemory;
vkFlushMappedMemoryRanges(vk.device, 1, &range);
if (d->devicebuf != VK_NULL_HANDLE)
{
VkBufferCopy bcr = {0};
bcr.srcOffset = 0;
bcr.dstOffset = 0;
bcr.size = d->offset;
bcr.srcOffset = d->flushed;
bcr.dstOffset = d->flushed;
bcr.size = d->offset - d->flushed;
if (!fence)
fence = VK_FencedBegin(NULL, 0);
vkCmdCopyBuffer(fence->cbuf, d->stagingbuf, d->devicebuf, 1, &bcr);
}
d->flushed = d->offset;
}
if (fence)
@ -1543,7 +1547,7 @@ void VKBE_RestartFrame(void)
for (i = 0; i < DB_MAX; i++)
{
vk.dynbuf[i] = vk.frame->dynbufs[i];
vk.dynbuf[i]->offset = 0;
vk.dynbuf[i]->offset = vk.dynbuf[i]->flushed = 0;
}
shaderstate.activepipeline = VK_NULL_HANDLE;
@ -3540,6 +3544,28 @@ static void BE_DrawMeshChain_Internal(void)
if (p->texgen == T_GEN_FULLBRIGHT && !TEXLOADED(shaderstate.curtexnums->fullbright))
continue;
if (p->prog)
{
vertexbuffers[VK_BUFF_TC] = shaderstate.batchvbo->texcoord.vk.buff;
vertexoffsets[VK_BUFF_TC] = shaderstate.batchvbo->texcoord.vk.offs;
vertexbuffers[VK_BUFF_LMTC] = shaderstate.batchvbo->lmcoord[0].vk.buff;
vertexoffsets[VK_BUFF_LMTC] = shaderstate.batchvbo->lmcoord[0].vk.offs;
BE_GenerateColourMods(vertcount, p, &vertexbuffers[VK_BUFF_COL], &vertexoffsets[VK_BUFF_COL]);
vertexbuffers[VK_BUFF_NORM] = shaderstate.staticbuf;
vertexoffsets[VK_BUFF_NORM] = sizeof(vec4_t)*65536;
vertexbuffers[VK_BUFF_SDIR] = shaderstate.staticbuf;
vertexoffsets[VK_BUFF_SDIR] = vertexoffsets[VK_BUFF_NORM] + sizeof(vec3_t)*65536;
vertexbuffers[VK_BUFF_TDIR] = shaderstate.staticbuf;
vertexoffsets[VK_BUFF_TDIR] = vertexoffsets[VK_BUFF_SDIR] + sizeof(vec3_t)*65536;
vkCmdBindVertexBuffers(vk.frame->cbuf, 0, VK_BUFF_MAX, vertexbuffers, vertexoffsets);
if (BE_SetupMeshProgram(p->prog, p, altshader->flags, idxcount))
vkCmdDrawIndexed(vk.frame->cbuf, idxcount, 1, idxfirst, 0, 0);
continue;
}
if (shaderstate.batchvbo)
{ //texcoords are all compatible with static arrays, supposedly
if (p->tcgen == TC_GEN_LIGHTMAP)
@ -3636,7 +3662,7 @@ qboolean VKBE_GenerateRTLightShader(unsigned int lmode)
(lmode & LSHADER_CUBE)?"#CUBE=1":"#CUBE=0")
, SUF_NONE, LIGHTPASS_SHADER);
}
if (!shaderstate.shader_rtlight[lmode]->prog)
if (shaderstate.shader_rtlight[lmode]->flags & SHADER_NODRAW)
return false;
return true;
}
@ -5679,7 +5705,7 @@ void VKBE_RenderShadowBuffer(struct vk_shadowbuffer *buf)
vkCmdBindVertexBuffers(vk.frame->cbuf, 0, 1, &buf->vbuffer, &buf->voffset);
vkCmdBindIndexBuffer(vk.frame->cbuf, buf->ibuffer, buf->ioffset, VK_INDEX_TYPE);
if (BE_SetupMeshProgram(depthonlyshader->prog, depthonlyshader->passes, 0, buf->numindicies))
if (BE_SetupMeshProgram(depthonlyshader->passes[0].prog, depthonlyshader->passes, 0, buf->numindicies))
vkCmdDrawIndexed(vk.frame->cbuf, buf->numindicies, 1, 0, 0, 0);
}
@ -5720,7 +5746,10 @@ qboolean VKBE_BeginShadowmap(qboolean isspot, uint32_t width, uint32_t height)
struct shadowmaps_s *shad = &shaderstate.shadow[isspot];
unsigned int sbuf;
vkCmdEndRenderPass(vk.frame->cbuf);
// const qboolean altqueue = false;
// if (!altqueue)
// vkCmdEndRenderPass(vk.frame->cbuf);
if (shad->width != width || shad->height != height)
{
@ -5898,40 +5927,53 @@ void VKBE_DoneShadows(void)
// struct shadowmaps_s *shad = &shaderstate.shadow[isspot];
VkViewport viewport;
// const qboolean altqueue = false;
//we've rendered the shadowmap, but now we need to blit it to the screen
//so set stuff back to the main view. FIXME: do these in batches to ease the load on tilers.
vkCmdEndRenderPass(vk.frame->cbuf);
/*
set_image_layout(vk.frame->cbuf, shad->image, VK_IMAGE_ASPECT_DEPTH_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT);
/*if (altqueue)
{
VkImageMemoryBarrier imgbarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
imgbarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
imgbarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
imgbarrier.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
imgbarrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
imgbarrier.image = image;
imgbarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
imgbarrier.subresourceRange.baseMipLevel = 0;
imgbarrier.subresourceRange.levelCount = 1;
imgbarrier.subresourceRange.baseArrayLayer = 0;
imgbarrier.subresourceRange.layerCount = 1;
imgbarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imgbarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, &imgbarrier);
vkCmdSetEvent(alt, shadowcompleteevent);
VKBE_FlushDynamicBuffers();
VK_Submit_Work();
vkCmdWaitEvents(main, 1, &shadowcompleteevent, barrierstuff);
vkCmdResetEvent(main, shadowcompleteevent);
}
*/
else*/
{
/*
set_image_layout(vk.frame->cbuf, shad->image, VK_IMAGE_ASPECT_DEPTH_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_ACCESS_SHADER_READ_BIT);
vkCmdBeginRenderPass(vk.frame->cbuf, &vk.rendertarg->restartinfo, VK_SUBPASS_CONTENTS_INLINE);
{
VkImageMemoryBarrier imgbarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
imgbarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
imgbarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
imgbarrier.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
imgbarrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
imgbarrier.image = image;
imgbarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
imgbarrier.subresourceRange.baseMipLevel = 0;
imgbarrier.subresourceRange.levelCount = 1;
imgbarrier.subresourceRange.baseArrayLayer = 0;
imgbarrier.subresourceRange.layerCount = 1;
imgbarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imgbarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, &imgbarrier);
}
*/
viewport.x = r_refdef.pxrect.x;
viewport.y = r_refdef.pxrect.y;//r_refdef.pxrect.maxheight - (r_refdef.pxrect.y+r_refdef.pxrect.height); //silly GL...
viewport.width = r_refdef.pxrect.width;
viewport.height = r_refdef.pxrect.height;
viewport.minDepth = 0;
viewport.maxDepth = shaderstate.depthrange;
vkCmdSetViewport(vk.frame->cbuf, 0, 1, &viewport);
vkCmdBeginRenderPass(vk.frame->cbuf, &vk.rendertarg->restartinfo, VK_SUBPASS_CONTENTS_INLINE);
viewport.x = r_refdef.pxrect.x;
viewport.y = r_refdef.pxrect.y;//r_refdef.pxrect.maxheight - (r_refdef.pxrect.y+r_refdef.pxrect.height); //silly GL...
viewport.width = r_refdef.pxrect.width;
viewport.height = r_refdef.pxrect.height;
viewport.minDepth = 0;
viewport.maxDepth = shaderstate.depthrange;
vkCmdSetViewport(vk.frame->cbuf, 0, 1, &viewport);
}
VKBE_SelectEntity(&r_worldentity);
@ -5979,7 +6021,7 @@ void VKBE_BeginShadowmapFace(void)
}
#endif
void VKBE_DrawWorld (batch_t **worldbatches, qbyte *vis)
void VKBE_DrawWorld (batch_t **worldbatches)
{
batch_t *batches[SHADER_SORT_COUNT];
RSpeedLocals();
@ -6007,7 +6049,7 @@ void VKBE_DrawWorld (batch_t **worldbatches, qbyte *vis)
//fixme: figure out some way to safely orphan this data so that we can throw the rest to a worker.
BE_GenModelBatches(batches, shaderstate.curdlight, BEM_STANDARD);
if (vis)
if (r_refdef.scenevis)
{
BE_UploadLightmaps(false);
@ -6021,7 +6063,7 @@ void VKBE_DrawWorld (batch_t **worldbatches, qbyte *vis)
r_worldentity.axis[2][2] = 1;
#ifdef RTLIGHTS
if (vis && r_shadow_realtime_world.ival)
if (r_refdef.scenevis && r_shadow_realtime_world.ival)
shaderstate.identitylighting = r_shadow_realtime_world_lightmaps.value;
else
#endif
@ -6029,18 +6071,30 @@ void VKBE_DrawWorld (batch_t **worldbatches, qbyte *vis)
shaderstate.identitylighting *= r_refdef.hdr_value;
shaderstate.identitylightmap = shaderstate.identitylighting / (1<<gl_overbright.ival);
VKBE_SelectMode(BEM_STANDARD);
if (r_lightprepass)
{
//set up render target for gbuffer
//draw opaque gbuffers
//switch render targets to lighting (renderpasses?)
//draw lpp lights
//revert to screen
//draw opaques again.
}
else
{
VKBE_SelectMode(BEM_STANDARD);
VKBE_SubmitMeshes(worldbatches, batches, SHADER_SORT_PORTAL, SHADER_SORT_DECAL);
RSpeedEnd(RSPEED_WORLD);
VKBE_SubmitMeshes(worldbatches, batches, SHADER_SORT_PORTAL, SHADER_SORT_DECAL);
RSpeedEnd(RSPEED_WORLD);
#ifdef RTLIGHTS
RSpeedRemark();
VKBE_SelectEntity(&r_worldentity);
Sh_DrawLights(vis);
RSpeedEnd(RSPEED_STENCILSHADOWS);
RSpeedRemark();
VKBE_SelectEntity(&r_worldentity);
Sh_DrawLights(r_refdef.scenevis);
RSpeedEnd(RSPEED_STENCILSHADOWS);
#endif
}
VKBE_SubmitMeshes(worldbatches, batches, SHADER_SORT_DECAL, SHADER_SORT_COUNT);

View File

@ -2568,6 +2568,7 @@ static void VK_Submit_DoWork(void)
VkPipelineStageFlags wsemstageflags[64];
VkSemaphore ssem[64];
VkQueue subqueue = NULL;
VkSubmitInfo subinfo[64];
unsigned int subcount = 0;
struct vkwork_s *work;
@ -2580,6 +2581,8 @@ static void VK_Submit_DoWork(void)
while(vk.work && !present && !waitfence && !fencedwork && subcount < countof(subinfo))
{
work = vk.work;
if (subcount && subqueue != work->queue)
break;
subinfo[subcount].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
subinfo[subcount].pNext = NULL;
subinfo[subcount].waitSemaphoreCount = work->semwait?1:0;
@ -2595,6 +2598,7 @@ static void VK_Submit_DoWork(void)
ssem[subcount] = work->semsignal;
waitfence = work->fencesignal;
fencedwork = work->fencedwork;
subqueue = work->queue;
subcount++;
@ -2608,7 +2612,7 @@ static void VK_Submit_DoWork(void)
if (subcount || waitfence)
{
RSpeedMark();
err = vkQueueSubmit(vk.queue_render, subcount, subinfo, waitfence);
err = vkQueueSubmit(subqueue, subcount, subinfo, waitfence);
if (err)
{
Con_Printf("ERROR: vkQueueSubmit: %i\n", err);
@ -2658,6 +2662,7 @@ void VK_Submit_Work(VkCommandBuffer cmdbuf, VkSemaphore semwait, VkPipelineStage
struct vkwork_s *work = Z_Malloc(sizeof(*work));
struct vkwork_s **link;
work->queue = vk.queue_render;
work->cmdbuf = cmdbuf;
work->semwait = semwait;
work->semwaitstagemask = semwaitstagemask;
@ -3074,7 +3079,7 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat
queueinf[0].pNext = NULL;
queueinf[0].queueFamilyIndex = vk.queuefam[0];
queueinf[0].queueCount = 1;
queueinf[0].pQueuePriorities = queue_priorities;
queueinf[0].pQueuePriorities = &queue_priorities[0];
queueinf[1].pNext = NULL;
queueinf[1].queueFamilyIndex = vk.queuefam[1];
queueinf[1].queueCount = 1;
@ -3083,7 +3088,7 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat
if (vk.queuefam[0] == vk.queuefam[1])
{
devinf.queueCreateInfoCount = 1;
if (queueprops[queueinf[0].queueFamilyIndex].queueCount >= 2 && vk_dualqueue.ival)
{
queueinf[0].queueCount = 2;

View File

@ -85,6 +85,9 @@
VKFunc(CmdCopyBuffer) \
VKFunc(CmdBlitImage) \
VKFunc(CmdPipelineBarrier) \
VKFunc(CmdSetEvent) \
VKFunc(CmdResetEvent) \
VKFunc(CmdWaitEvents) \
VKFunc(CreateDescriptorSetLayout) \
VKFunc(DestroyDescriptorSetLayout) \
VKFunc(CreatePipelineLayout) \
@ -219,6 +222,11 @@ struct vk_rendertarg_cube
struct vk_rendertarg face[6];
};
#define VQ_RENDER 0
#define VQ_PRESENT 1
#define VQ_ALTRENDER 2
#define VQ_ALTRENDER_COUNT 16
#define VQ_COUNT 3
extern struct vulkaninfo_s
{
unsigned short triplebuffer;
@ -228,10 +236,11 @@ extern struct vulkaninfo_s
VkDevice device;
VkPhysicalDevice gpu;
VkSurfaceKHR surface;
uint32_t queuefam[2]; //queue families, render+present
uint32_t queuenum[2]; //queue families, render+present
uint32_t queuefam[VQ_COUNT];
uint32_t queuenum[VQ_COUNT];
VkQueue queue_render;
VkQueue queue_present;
VkQueue queue_alt[1];
VkPhysicalDeviceMemoryProperties memory_properties;
VkCommandPool cmdpool;
@ -265,8 +274,9 @@ extern struct vulkaninfo_s
} *descpool;
struct dynbuffer
{
size_t offset;
size_t size;
size_t flushed; //size already copied to the gpu
size_t offset; //size written by the cpu (that might not yet be flushed)
size_t size; //maximum buffer size
size_t align;
VkBuffer stagingbuf;
VkDeviceMemory stagingmemory;
@ -305,6 +315,7 @@ extern struct vulkaninfo_s
struct vkwork_s
{
struct vkwork_s *next;
VkQueue queue;
VkCommandBuffer cmdbuf;
VkSemaphore semwait;
VkPipelineStageFlags semwaitstagemask;
@ -366,7 +377,7 @@ batch_t *VKBE_GetTempBatch(void);
void VKBE_GenBrushModelVBO(model_t *mod);
void VKBE_ClearVBO(vbo_t *vbo);
void VKBE_UploadAllLightmaps(void);
void VKBE_DrawWorld (batch_t **worldbatches, qbyte *vis);
void VKBE_DrawWorld (batch_t **worldbatches);
qboolean VKBE_LightCullModel(vec3_t org, model_t *model);
void VKBE_SelectEntity(entity_t *ent);
qboolean VKBE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsigned int lmode);