d3d11: stripped the reflection stuff from the d3d11 renderer. we'll do that stuff explicitly instead of having to deal with microsoft's api. its just more reliable.

openal: doppler now applies to openal more consistently.
vulkan: vk_loadglsl cvar enables vk_nv_glsl_shader, with support for existing glsl shaders (still no permutations for now). needs !!samps stuff.
vulkan: r_renderscale now partly works. r_fxaa also works under specific circumstances. needs more work. still no bloom or projections stuff.
menu_download: got a few tweaks to improve it, including zips. I still want to handle engine updates with this stuff, but that can wait for later.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5008 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2016-07-26 11:47:59 +00:00
parent ec623409ff
commit eccfe6b560
43 changed files with 6506 additions and 5335 deletions

View file

@ -173,6 +173,7 @@ cvar_t cl_countpendingpl = CVARD("cl_countpendingpl", "0", "If set to 1, packet
cvar_t cl_standardchat = CVARFD("cl_standardchat", "0", CVAR_ARCHIVE, "Disables auto colour coding in chat messages.");
cvar_t msg_filter = CVARD("msg_filter", "0", "Filter out chat messages: 0=neither. 1=broadcast chat. 2=team chat. 3=all chat.");
cvar_t msg_filter_frags = CVARD("msg_filter_frags", "0", "Prevents frag messages from appearing on the console.");
cvar_t msg_filter_pickups = CVARD("msg_filter_pickups", "0", "Prevents pickup messages from appearing on the console. This would normally be filtered by 'msg 1', but nq servers cannot respect that (nor nq mods running in qw servers).");
cvar_t cl_standardmsg = CVARFD("cl_standardmsg", "0", CVAR_ARCHIVE, "Disables auto colour coding in console prints.");
cvar_t cl_parsewhitetext = CVARD("cl_parsewhitetext", "1", "When parsing chat messages, enable support for messages like: red{white}red");

View file

@ -268,7 +268,7 @@ char *svc_nqstrings[] =
"NEW PROTOCOL(88)" //88
};
extern cvar_t requiredownloads, cl_standardchat, msg_filter, msg_filter_frags, cl_countpendingpl, cl_download_mapsrc;
extern cvar_t requiredownloads, cl_standardchat, msg_filter, msg_filter_frags, msg_filter_pickups, cl_countpendingpl, cl_download_mapsrc;
int oldparsecountmod;
int parsecountmod;
double parsecounttime;
@ -5948,12 +5948,13 @@ void CL_ParsePrint(char *msg, int level)
}
else
{
#ifdef PLUGINS
if (Plug_ServerMessage(printtext, level))
#endif
#ifdef CSQC_DAT
if (!CSQC_ParsePrint(printtext, level))
#endif
#ifdef PLUGINS
if (Plug_ServerMessage(printtext, level))
#endif
if (!Stats_ParsePickups(printtext) || !msg_filter_pickups.ival)
if (!Stats_ParsePrintLine(printtext) || !msg_filter_frags.ival)
CL_PrintStandardMessage(printtext, level);
}
@ -7293,7 +7294,10 @@ void CLNQ_ParseServerMessage (void)
s = MSG_ReadString ();
if (*s == 1 || *s == 2)
{
//FIXME: should be using the first char of the line, not the first char of the last segment.
CL_ParsePrint(s+1, PRINT_CHAT);
}
else if (CLNQ_ParseNQPrints(s))
break;
else

View file

@ -1620,7 +1620,8 @@ qboolean Stats_HaveFlags(int mode);
qboolean Stats_HaveKills(void);
float Stats_GetLastOwnFrag(int seat, char *res, int reslen);
void VARGS Stats_Message(char *msg, ...) LIKEPRINTF(1);
qboolean Stats_ParsePrintLine(char *line);
qboolean Stats_ParsePrintLine(const char *line);
qboolean Stats_ParsePickups(const char *line);
void Stats_NewMap(void);
void Stats_Clear(void);
void Stats_Init(void);

View file

@ -275,25 +275,24 @@ qboolean Con_NameForNum(int num, char *buffer, int buffersize)
}
#ifdef QTERM
void QT_Update(void)
void QT_Kill(qterm_t *qt, qboolean killconsole)
{
char buffer[2048];
DWORD ret;
qterm_t *qt;
qterm_t *prev = NULL;
for (qt = qterms; qt; qt = (prev=qt)->next)
{
if (!qt->running)
{
if (Con_IsActive(qt->console))
continue;
qterm_t **link;
qt->console->close = NULL;
qt->console->userdata = NULL;
qt->console->redirect = NULL;
if (killconsole)
Con_Destroy(qt->console);
if (prev)
prev->next = qt->next;
else
qterms = qt->next;
//yes this loop will crash if you're not careful. it makes it easier to debug.
for (link = &qterms; ; link = &(*link)->next)
{
if (*link == qt)
{
*link = qt->next;
break;
}
}
CloseHandle(qt->pipein);
CloseHandle(qt->pipeout);
@ -303,8 +302,16 @@ void QT_Update(void)
CloseHandle(qt->process);
Z_Free(qt);
break; //be lazy.
}
}
void QT_Update(void)
{
char buffer[2048];
DWORD ret;
qterm_t *qt, *n;
for (qt = qterms; qt; )
{
if (qt->running)
{
if (WaitForSingleObject(qt->process, 0) == WAIT_TIMEOUT)
{
if ((ret=GetFileSize(qt->pipeout, NULL)))
@ -313,22 +320,31 @@ void QT_Update(void)
{
ReadFile(qt->pipeout, buffer, sizeof(buffer)-32, &ret, NULL);
buffer[ret] = '\0';
Con_PrintCon(qt->console, buffer);
Con_PrintCon(qt->console, buffer, PFS_NOMARKUP);
}
}
}
else
{
Con_PrintCon(qt->console, "Process ended\n");
Con_PrintCon(qt->console, "Process ended\n", PFS_NOMARKUP);
qt->running = false;
}
}
n = qt->next;
if (!qt->running)
{
if (!Con_IsActive(qt->console))
QT_Kill(qt, true);
}
qt = n;
}
}
void QT_KeyPress(void *user, int key)
qboolean QT_KeyPress(console_t *con, unsigned int unicode, int key)
{
qbyte k[2];
qterm_t *qt = user;
qterm_t *qt = con->userdata;
DWORD send = key; //get around a gcc warning
@ -341,16 +357,24 @@ void QT_KeyPress(void *user, int key)
{
// *k = '\r';
// WriteFile(qt->pipein, k, 1, &key, NULL);
// Con_PrintCon(k, &qt->console);
// Con_PrintCon(k, &qt->console, PFS_NOMARKUP);
*k = '\n';
}
if (GetFileSize(qt->pipein, NULL)<512)
// if (GetFileSize(qt->pipein, NULL)<512)
{
WriteFile(qt->pipein, k, 1, &send, NULL);
Con_PrintCon(qt->console, k);
Con_PrintCon(qt->console, k, PFS_NOMARKUP);
}
}
return;
return true;
}
qboolean QT_Close(struct console_s *con, qboolean force)
{
qterm_t *qt = con->userdata;
QT_Kill(qt, false);
return true;
}
void QT_Create(char *command)
@ -419,8 +443,10 @@ void QT_Create(char *command)
qt->console = Con_Create("QTerm", 0);
qt->console->redirect = QT_KeyPress;
Con_PrintCon(qt->console, "Started Process\n");
Con_SetVisible(qt->console);
qt->console->close = QT_Close;
qt->console->userdata = qt;
Con_PrintCon(qt->console, "Started Process\n", PFS_NOMARKUP);
Con_SetActive(qt->console);
qt->next = qterms;
qterms = activeqterm = qt;

View file

@ -780,6 +780,22 @@ static int Stats_ExtractName(char **line)
return bm;
}
qboolean Stats_ParsePickups(const char *line)
{
#ifndef NOLEGACY
//fixme: rework this to support custom strings, with custom pickup icons
if (!Q_strncmp(line, "You got the ", 12)) //weapons, ammo, keys, powerups
return true;
if (!Q_strncmp(line, "You got armor", 13)) //caaake...
return true;
if (!Q_strncmp(line, "You get ", 8)) //backpackets
return true;
if (!Q_strncmp(line, "You receive ", 12)) //%i health\n
return true;
#endif
return false;
}
qboolean Stats_ParsePrintLine(char *line)
{
statmessage_t *ms;

View file

@ -6,6 +6,45 @@
#ifdef DOWNLOADMENU
//whole load of extra args for the downloads menu (for the downloads menu to handle engine updates).
#ifdef VKQUAKE
#define PHPVK "&vk=1"
#else
#define PHPVK
#endif
#ifdef GLQUAKE
#define PHPGL "&gl=1"
#else
#define PHPGL
#endif
#ifdef D3DQUAKE
#define PHPD3D "&d3d=1"
#else
#define PHPD3D
#endif
#ifdef MINIMAL
#define PHPMIN "&min=1"
#else
#define PHPMIN
#endif
#ifdef NOLEGACY
#define PHPLEG "&leg=0"
#else
#define PHPLEG "&leg=1"
#endif
#if defined(_DEBUG) || defined(DEBUG)
#define PHPDBG "&dbg=1"
#else
#define PHPDBG
#endif
#ifndef SVNREVISION
#define SVNREVISION -
#endif
#define DOWNLOADABLESARGS "?ver=" STRINGIFY(SVNREVISION) PHPVK PHPGL PHPD3D PHPMIN PHPLEG PHPDBG
extern cvar_t fs_downloads_url;
#define INSTALLEDFILES "installed.lst" //the file that resides in the quakedir (saying what's installed).
@ -14,6 +53,7 @@ extern cvar_t fs_downloads_url;
#define DPF_DISPLAYVERSION 4 //some sort of conflict, the package is listed twice, so show versions so the user knows what's old.
#define DPF_FORGETONUNINSTALL 8 //for previously installed packages, remove them from the list if there's no current version any more (should really be automatic if there's no known mirrors)
#define DPF_UNKNOWNVERSION 16 //we have a file with this name already, with no idea where it came from.
#define DPF_HIDDEN 32 //wrong arch, file conflicts, etc. still listed if actually installed.
void CL_StartCinematicOrMenu(void);
@ -23,17 +63,27 @@ static char *downloadablelistnameprefix[countof(downloadablelist)];
static char downloadablelistreceived[countof(downloadablelist)]; //well
static int numdownloadablelists = 0;
#define THISARCH PLATFORM "_" ARCH_CPU_POSTFIX
typedef struct package_s {
char fullname[256];
char *name;
struct package_s *override; //the package that obscures this one (later version, or whatever)
unsigned int trymirrors;
char *mirror[8];
char dest[MAX_QPATH];
char gamedir[16];
enum fs_relative fsroot;
char version[16];
int extract;
char *arch;
enum
{
EXTRACT_COPY, //just copy the download over
EXTRACT_XZ, //give the download code a write filter so that it automatically decompresses on the fly
EXTRACT_GZ, //give the download code a write filter so that it automatically decompresses on the fly
EXTRACT_ZIP //extract stuff once it completes. kinda sucky.
} extract;
struct packagedep_s
{
@ -41,8 +91,11 @@ typedef struct package_s {
enum
{
DEP_CONFLICT,
DEP_FILECONFLICT, //don't install if this file already exists.
DEP_REQUIRE,
DEP_RECOMMEND, //like depend, but uninstalling will not bubble.
DEP_FILE
} dtype;
char name[1];
} *deps;
@ -67,6 +120,35 @@ static int numpackages;
static int autoupdatesetting = -1;
#endif
static qboolean MD_CheckFile(const char *filename, enum fs_relative base)
{
vfsfile_t *f = FS_OpenVFS(filename, "rb", base);
if (f)
{
VFS_CLOSE(f);
return true;
}
return false;
}
void MD_AddDep(package_t *p, int deptype, const char *depname)
{
struct packagedep_s *nd, **link;
//no dupes.
for (link = &p->deps; (nd=*link) ; link = &nd->next)
{
if (nd->dtype == deptype && !strcmp(nd->name, depname))
return;
}
//add it on the end, preserving order.
nd = Z_Malloc(sizeof(*nd) + strlen(depname));
nd->dtype = deptype;
strcpy(nd->name, depname);
nd->next = *link;
*link = nd;
}
static void M_DL_AddSubList(const char *url, const char *prefix)
{
int i;
@ -93,6 +175,7 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con
char line[1024];
package_t *p, *o;
package_t *first = NULL;
struct packagedep_s *dep;
char *sl;
vfsfile_t *pf;
@ -191,15 +274,14 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con
char *url = NULL;
char *gamedir = NULL;
char *ver = NULL;
struct packagedep_s *deps = NULL, *nd;
int extract = 0;
int extract = EXTRACT_COPY;
int i;
p = Z_Malloc(sizeof(*p));
for (i = 1; i < argc; i++)
{
char *arg = Cmd_Argv(i);
if (!strncmp(arg, "file=", 5))
file = arg+5;
else if (!strncmp(arg, "url=", 4))
if (!strncmp(arg, "url=", 4))
url = arg+4;
else if (!strncmp(arg, "gamedir=", 8))
gamedir = arg+8;
@ -207,67 +289,53 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con
ver = arg+4;
else if (!strncmp(arg, "v=", 2))
ver = arg+2;
// else if (!strncmp(arg, "arch=", 5))
// arch = arg+5;
else if (!strncmp(arg, "arch=", 5))
/*arch = arg+5*/;
else if (!strncmp(arg, "file=", 5))
{
if (!file)
file = arg+5;
MD_AddDep(p, DEP_FILE, arg+5);
}
else if (!strncmp(arg, "extract=", 8))
{
if (!strcmp(arg+8, "xz"))
extract = 1;
extract = EXTRACT_XZ;
else if (!strcmp(arg+8, "gz"))
extract = 2;
extract = EXTRACT_GZ;
else if (!strcmp(arg+8, "zip"))
extract = EXTRACT_ZIP;
else
Con_Printf("Unknown decompression method: %s\n", arg+8);
}
else if (!strncmp(arg, "depend=", 7))
{
arg += 7;
nd = Z_Malloc(sizeof(*nd) + strlen(arg));
nd->dtype = DEP_REQUIRE;
strcpy(nd->name, arg);
nd->next = deps;
deps = nd;
}
MD_AddDep(p, DEP_REQUIRE, arg+7);
else if (!strncmp(arg, "conflict=", 9))
{
arg += 9;
nd = Z_Malloc(sizeof(*nd) + strlen(arg));
nd->dtype = DEP_CONFLICT;
strcpy(nd->name, arg);
nd->next = deps;
deps = nd;
}
MD_AddDep(p, DEP_CONFLICT, arg+9);
else if (!strncmp(arg, "fileconflict=", 13))
MD_AddDep(p, DEP_FILECONFLICT, arg+13);
else if (!strncmp(arg, "recommend=", 10))
{
arg += 10;
nd = Z_Malloc(sizeof(*nd) + strlen(arg));
nd->dtype = DEP_RECOMMEND;
strcpy(nd->name, arg);
nd->next = deps;
deps = nd;
}
MD_AddDep(p, DEP_RECOMMEND, arg+10);
else
break;
{
Con_DPrintf("Unknown package property\n");
}
}
p = Z_Malloc(sizeof(*p));
if (*prefix)
Q_snprintfz(p->fullname, sizeof(p->fullname), "%s/%s", prefix, Cmd_Argv(0));
else
Q_snprintfz(p->fullname, sizeof(p->fullname), "%s", Cmd_Argv(0));
p->name = COM_SkipPath(p->fullname);
if (!file)
file = p->name;
if (!gamedir)
gamedir = defaultgamedir;
Q_snprintfz(p->dest, sizeof(p->dest), "%s", file);
Q_strncpyz(p->version, ver?ver:"", sizeof(p->version));
Q_snprintfz(p->gamedir, sizeof(p->gamedir), "%s", gamedir);
p->fsroot = FS_ROOT;
p->extract = extract;
p->deps = deps;
if (url && (!strncmp(url, "http://", 7) || !strncmp(url, "https://", 8)))
p->mirror[0] = Z_StrDup(url);
@ -277,10 +345,12 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con
char *ext = "";
if (!url)
{
if (extract == 1)
if (extract == EXTRACT_XZ)
ext = ".xz";
else if (extract == 2)
else if (extract == EXTRACT_GZ)
ext = ".gz";
else if (extract == EXTRACT_ZIP)
ext = ".zip";
url = file;
}
for (m = 0; m < nummirrors; m++)
@ -306,7 +376,7 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con
p->name = sl+1;
p->mirror[0] = Z_StrDup(Cmd_Argv(1));
Q_strncpyz(p->dest, Cmd_Argv(2), sizeof(p->dest));
MD_AddDep(p, DEP_FILE, Cmd_Argv(2));
Q_strncpyz(p->version, Cmd_Argv(3), sizeof(p->version));
Q_strncpyz(p->gamedir, Cmd_Argv(4), sizeof(p->gamedir));
if (!strcmp(p->gamedir, "../"))
@ -324,33 +394,84 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con
p->fsroot = FS_ROOT;
}
}
p->flags = flags;
if (p->arch && Q_strcasecmp(p->arch, THISARCH))
p->flags |= DPF_HIDDEN;
for (dep = p->deps; dep; dep = dep->next)
{
if (dep->dtype == DEP_FILECONFLICT)
{
const char *n;
if (*p->gamedir)
pf = FS_OpenVFS(va("%s/%s", p->gamedir, p->dest), "rb", p->fsroot);
n = va("%s/%s", p->gamedir, dep->name);
else
pf = FS_OpenVFS(p->dest, "rb", p->fsroot);
if (pf)
VFS_CLOSE(pf);
n = dep->name;
if (MD_CheckFile(n, p->fsroot))
p->flags |= DPF_HIDDEN;
}
}
if (flags & DPF_HAVEAVERSION)
{
if (!pf)
Con_Printf("WARNING: %s no longer exists\n", p->fullname);
for (dep = p->deps; dep; dep = dep->next)
{
char *n;
if (dep->dtype != DEP_FILE)
continue;
if (*p->gamedir)
n = va("%s/%s", p->gamedir, dep->name);
else
n = dep->name;
pf = FS_OpenVFS(n, "rb", p->fsroot);
if (pf)
VFS_CLOSE(pf);
else
Con_Printf("WARNING: %s (%s) no longer exists\n", p->fullname, n);
}
}
else
{
for (dep = p->deps; dep; dep = dep->next)
{
char *n;
struct packagedep_s *odep;
if (dep->dtype != DEP_FILE)
continue;
if (*p->gamedir)
n = va("%s/%s", p->gamedir, dep->name);
else
n = dep->name;
pf = FS_OpenVFS(n, "rb", p->fsroot);
if (pf)
{
VFS_CLOSE(pf);
for (o = availablepackages; o; o = o->next)
{
if (o->flags & DPF_HAVEAVERSION)
if (!strcmp(p->dest, o->dest) && p->fsroot == o->fsroot)
{
if (!strcmp(p->gamedir, o->gamedir) && p->fsroot == o->fsroot)
if (strcmp(p->fullname, o->fullname) || strcmp(p->version, o->version))
{
for (odep = o->deps; odep; odep = odep->next)
{
if (!strcmp(dep->name, odep->name))
break;
}
if (pf && !o)
flags |= DPF_UNKNOWNVERSION;
if (odep)
break;
}
}
}
if (!o)
{
p->flags |= DPF_UNKNOWNVERSION;
break;
}
}
}
}
p->flags = flags;
p->next = first;
first = p;
@ -360,10 +481,33 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con
return first;
}
static void COM_QuotedConcat(const char *cat, char *buf, size_t bufsize)
{
qboolean haswhite = false;
const unsigned char *gah;
for (gah = (const unsigned char*)cat; *gah; gah++)
{
if (*gah <= ' ' || *gah == '$' || *gah == '\"')
break;
}
if (*gah || *cat == '\\' ||
strstr(cat, "//") || strstr(cat, "/*"))
{ //contains some dodgy stuff.
size_t curlen = strlen(buf);
buf += curlen;
bufsize -= curlen;
COM_QuotedString(cat, buf, bufsize, false);
}
else
{ //okay, no need for quotes.
Q_strncatz(buf, cat, bufsize);
}
}
static void WriteInstalledPackages(void)
{
char *s;
package_t *p;
struct packagedep_s *dep;
vfsfile_t *f = FS_OpenVFS(INSTALLEDFILES, "wb", FS_ROOT);
if (!f)
{
@ -377,8 +521,56 @@ static void WriteInstalledPackages(void)
{
if (p->flags & DPF_HAVEAVERSION)
{
s = va("\"%s\" \"file=%s\" \"ver=%s\" \"gamedir=%s\"\n", p->fullname, p->dest, p->version, p->gamedir);
VFS_WRITE(f, s, strlen(s));
char buf[8192];
buf[0] = 0;
COM_QuotedString(p->fullname, buf, sizeof(buf), false);
if (*p->version)
{
Q_strncatz(buf, " ", sizeof(buf));
COM_QuotedConcat(va("ver=%s", p->version), buf, sizeof(buf));
}
//if (*p->gamedir)
{
Q_strncatz(buf, " ", sizeof(buf));
COM_QuotedConcat(va("gamedir=%s", p->gamedir), buf, sizeof(buf));
}
if (p->arch)
{
Q_strncatz(buf, " ", sizeof(buf));
COM_QuotedConcat(va("arch=%s", p->arch), buf, sizeof(buf));
}
for (dep = p->deps; dep; dep = dep->next)
{
if (dep->dtype == DEP_FILE)
{
Q_strncatz(buf, " ", sizeof(buf));
COM_QuotedConcat(va("file=%s", dep->name), buf, sizeof(buf));
}
else if (dep->dtype == DEP_REQUIRE)
{
Q_strncatz(buf, " ", sizeof(buf));
COM_QuotedConcat(va("depend=%s", dep->name), buf, sizeof(buf));
}
else if (dep->dtype == DEP_CONFLICT)
{
Q_strncatz(buf, " ", sizeof(buf));
COM_QuotedConcat(va("conflict=%s", dep->name), buf, sizeof(buf));
}
else if (dep->dtype == DEP_FILECONFLICT)
{
Q_strncatz(buf, " ", sizeof(buf));
COM_QuotedConcat(va("fileconflict=%s", dep->name), buf, sizeof(buf));
}
else if (dep->dtype == DEP_RECOMMEND)
{
Q_strncatz(buf, " ", sizeof(buf));
COM_QuotedConcat(va("recommend=%s", dep->name), buf, sizeof(buf));
}
}
Q_strncatz(buf, "\n", sizeof(buf));
VFS_WRITE(f, buf, strlen(buf));
}
}
@ -399,19 +591,11 @@ static qboolean ComparePackages(package_t **l, package_t *p)
else if (v == 0)
{
if (!strcmp(p->version, (*l)->version))
if (!strcmp((*l)->dest, p->dest))
{ /*package matches, free, don't add*/
int i;
for (i = 0; i < countof(p->mirror); i++)
{
Z_Free((*l)->mirror[i]);
(*l)->mirror[i] = p->mirror[i];
}
(*l)->extract = p->extract;
(*l)->flags |= p->flags;
(*l)->flags &= ~DPF_FORGETONUNINSTALL;
BZ_Free(p);
return true;
if (!strcmp(p->gamedir, (*l)->gamedir))
// if (!strcmp((*l)->fullname, p->fullname))
{ /*package matches, free the new one, don't add*/
p->override = *l;
return false;
}
p->flags |= DPF_DISPLAYVERSION;
@ -482,7 +666,12 @@ static void MD_Draw (int x, int y, struct menucustom_s *c, struct menu_s *m)
if (p)
{
fl = p->flags & (DPF_HAVEAVERSION | DPF_WANTTOINSTALL);
if (p->download)
if (p->flags & DPF_HIDDEN)
{
Draw_FunString (x+4, y, "---");
return;
}
else if (p->download)
Draw_FunString (x+4, y, va("%i", (int)p->download->qdownload.percent));
else if (p->trymirrors)
Draw_FunString (x+4, y, "PND");
@ -500,7 +689,7 @@ static void MD_Draw (int x, int y, struct menucustom_s *c, struct menu_s *m)
}
break;
case DPF_HAVEAVERSION:
Draw_FunString (x, y, "REM");
Draw_FunString (x, y, "DEL");
break;
case DPF_WANTTOINSTALL:
Draw_FunString (x, y, "GET");
@ -582,11 +771,28 @@ static void MD_RemovePackage(package_t *package)
static void MD_AddPackage(package_t *package)
{
package_t *o;
struct packagedep_s *dep;
struct packagedep_s *dep, *dep2;
qboolean replacing = false;
if (package->flags & DPF_WANTTOINSTALL)
return; //looks like its already picked.
//any file-conflicts prevent the package from being installable.
//this is mostly for pak1.pak
for (dep = package->deps; dep; dep = dep->next)
{
if (dep->dtype == DEP_FILECONFLICT)
{
const char *n;
if (*package->gamedir)
n = va("%s/%s", package->gamedir, dep->name);
else
n = dep->name;
if (MD_CheckFile(n, package->fsroot))
return;
}
}
package->flags |= DPF_WANTTOINSTALL;
//first check to see if we're replacing a different version of the same package
@ -604,8 +810,24 @@ static void MD_AddPackage(package_t *package)
}
else
{ //two packages with the same filename are always mutually incompatible, but with totally separate dependancies etc.
if (!strcmp(o->dest, package->dest))
qboolean remove = false;
for (dep = package->deps; dep; dep = dep->next)
{
if (dep->dtype == DEP_FILE)
for (dep2 = o->deps; dep2; dep2 = dep2->next)
{
if (dep2->dtype == DEP_FILE)
if (!strcmp(dep->name, dep2->name))
{
MD_RemovePackage(o);
remove = true;
break;
}
}
if (remove)
break;
}
//fixme: zip content conflicts
}
}
}
@ -647,13 +869,16 @@ static void MD_AddPackage(package_t *package)
static qboolean MD_Key (struct menucustom_s *c, struct menu_s *m, int key, unsigned int unicode)
{
package_t *p, *p2;
struct packagedep_s *dep, *dep2;
p = c->dptr;
if (p->flags & DPF_HIDDEN)
return false;
if (key == K_ENTER || key == K_KP_ENTER || key == K_MOUSE1)
{
if (p->flags & DPF_UNKNOWNVERSION)
p->flags &= ~DPF_UNKNOWNVERSION;
else if (p->flags & DPF_WANTTOINSTALL)
if (p->flags & DPF_WANTTOINSTALL)
MD_RemovePackage(p);
// else if (p->flags & DPF_UNKNOWNVERSION)
// p->flags &= ~DPF_UNKNOWNVERSION;
else
MD_AddPackage(p);
@ -664,8 +889,21 @@ static qboolean MD_Key (struct menucustom_s *c, struct menu_s *m, int key, unsig
{
if (p == p2)
continue;
if (!strcmp(p->dest, p2->dest))
for (dep = p->deps; dep; dep = dep->next)
{
if (dep->dtype != DEP_FILE)
continue;
for (dep2 = p2->deps; dep2; dep2 = dep2->next)
{
if (dep2->dtype != DEP_FILE)
continue;
if (!strcmp(dep->name, dep2->name))
{
p2->flags &= ~DPF_WANTTOINSTALL;
break;
}
}
}
}
}
else
@ -731,6 +969,55 @@ qboolean MD_PopMenu (union menuoption_s *mo,struct menu_s *m,int key)
vfsfile_t *FS_XZ_DecompressWriteFilter(vfsfile_t *infile);
vfsfile_t *FS_GZ_DecompressWriteFilter(vfsfile_t *outfile, qboolean autoclosefile);
static char *MD_GetTempName(package_t *p)
{
struct packagedep_s *dep;
char *destname, *t, *ts;
//always favour a file so that we can rename safely without needing a copy.
for (dep = p->deps; dep; dep = dep->next)
{
if (dep->dtype != DEP_FILE)
continue;
if (*p->gamedir)
destname = va("%s/%s.tmp", p->gamedir, dep->name);
else
destname = va("%s.tmp", dep->name);
return Z_StrDup(destname);
}
ts = Z_StrDup(p->name);
for (t = ts; *t; t++)
{
switch(*t)
{
case '/':
case '?':
case '<':
case '>':
case '\\':
case ':':
case '*':
case '|':
case '\"':
case '.':
*t = '_';
break;
default:
break;
}
}
if (*ts)
{
if (*p->gamedir)
destname = va("%s/%s.tmp", p->gamedir, ts);
else
destname = va("%s.tmp", ts);
}
else
destname = va("%x.tmp", (unsigned int)(quintptr_t)p);
Z_Free(ts);
return Z_StrDup(destname);
}
static void Menu_Download_Got(struct dl_download *dl);
static void MD_StartADownload(void)
{
@ -767,21 +1054,19 @@ static void MD_StartADownload(void)
continue;
}
if (*p->gamedir)
temp = va("%s/%s.tmp", p->gamedir, p->dest);
else
temp = va("%s.tmp", p->dest);
temp = MD_GetTempName(p);
//FIXME: we should lock in the temp path, in case the user foolishly tries to change gamedirs.
FS_CreatePath(temp, p->fsroot);
switch (p->extract)
{
case 0:
case EXTRACT_ZIP:
case EXTRACT_COPY:
tmpfile = FS_OpenVFS(temp, "wb", p->fsroot);
break;
#ifdef AVAIL_XZDEC
case 1:
case EXTRACT_XZ:
{
vfsfile_t *raw;
raw = FS_OpenVFS(temp, "wb", p->fsroot);
@ -792,7 +1077,7 @@ static void MD_StartADownload(void)
break;
#endif
#ifdef AVAIL_GZDEC
case 2:
case EXTRACT_GZ:
{
vfsfile_t *raw;
raw = FS_OpenVFS(temp, "wb", p->fsroot);
@ -813,6 +1098,7 @@ static void MD_StartADownload(void)
{
Con_Printf("Downloading %s\n", p->fullname);
p->download->file = tmpfile;
p->download->user_ctx = temp;
#ifdef MULTITHREAD
DL_CreateThread(p->download, NULL, NULL);
@ -832,22 +1118,11 @@ static void MD_StartADownload(void)
}
}
static qboolean MD_CheckFile(char *filename, enum fs_relative base)
{
vfsfile_t *f = FS_OpenVFS(filename, "rb", base);
if (f)
{
VFS_CLOSE(f);
return true;
}
return false;
}
static qboolean MD_ApplyDownloads (union menuoption_s *mo,struct menu_s *m,int key)
{
if (key == K_ENTER || key == K_KP_ENTER || key == K_MOUSE1)
{
package_t *last = NULL, *p;
package_t *p, *o, **link;
#ifdef HAVEAUTOUPDATE
if (autoupdatesetting != -1)
@ -858,45 +1133,77 @@ static qboolean MD_ApplyDownloads (union menuoption_s *mo,struct menu_s *m,int k
#endif
//delete any that don't exist
for (p = availablepackages; p ; p=p->next)
for (link = &availablepackages; *link ; )
{
p = *link;
if (!(p->flags&DPF_WANTTOINSTALL) && (p->flags&DPF_HAVEAVERSION))
{ //if we don't want it but we have it anyway:
qboolean reloadpacks = false;
struct packagedep_s *dep;
for (dep = p->deps; dep; dep = dep->next)
{
if (dep->dtype == DEP_FILE)
{
if (!reloadpacks)
{
char ext[8];
COM_FileExtension(p->dest, ext, sizeof(ext));
COM_FileExtension(dep->name, ext, sizeof(ext));
if (!stricmp(ext, "pak") || !stricmp(ext, "pk3"))
{
reloadpacks = true;
FS_UnloadPackFiles();
FS_Remove(p->dest, p->fsroot);
FS_ReloadPackFiles();
}
}
if (*p->gamedir)
FS_Remove(va("%s/%s", p->gamedir, dep->name), p->fsroot);
else
{
FS_Remove(p->dest, p->fsroot);
FS_Remove(dep->name, p->fsroot);
}
}
if (reloadpacks)
FS_ReloadPackFiles();
//if its no longer readable then we were successful.
//this should give 'success' in the case of it being readonly or not existing in the first place (which is why we didn't depend upon FS_Remove succeeding).
if (!MD_CheckFile(p->dest, p->fsroot))
p->flags &= ~DPF_UNKNOWNVERSION;
p->flags &= ~DPF_HAVEAVERSION;
//make sure it actually got wiped. if there's still a file there then something went screwy.
//we don't reliably know if the remove actually succeeded or failed.
for (dep = p->deps; dep; dep = dep->next)
{
p->flags&=~DPF_HAVEAVERSION;
WriteInstalledPackages();
if (dep->dtype == DEP_FILE)
{
const char *n;
if (*p->gamedir)
n = va("%s/%s", p->gamedir, dep->name);
else
n = dep->name;
if (MD_CheckFile(n, p->fsroot))
{
p->flags |= DPF_UNKNOWNVERSION;
break;
}
}
}
WriteInstalledPackages();
if (p->flags & DPF_FORGETONUNINSTALL)
{
if (last)
last->next = p->next;
else
availablepackages = p->next;
*link = p->next;
// BZ_Free(p);
for (o = availablepackages; o; o = o->next)
{
if (o->override == p)
o->override = NULL;
}
return true;
p->flags |= DPF_HIDDEN;
// BZ_Free(p);
continue;
}
}
last = p;
link = &(*link)->next;
}
//and flag any new/updated ones for a download
@ -947,6 +1254,11 @@ void M_AddItemsToDownloadMenu(menu_t *m)
{
if (strncmp(p->fullname, info->pathprefix, prefixlen))
continue;
if ((p->flags & DPF_HIDDEN) && !(p->flags & DPF_HAVEAVERSION))
continue;
if (p->override)
continue;
slash = strchr(p->fullname+prefixlen, '/');
if (slash)
{
@ -997,7 +1309,7 @@ void M_Download_UpdateStatus(struct menu_s *m)
{
if (!downloadablelistreceived[info->parsedsourcenum])
{
dl = HTTP_CL_Get(downloadablelist[info->parsedsourcenum], NULL, M_DL_Notification);
dl = HTTP_CL_Get(va("%s"DOWNLOADABLESARGS, downloadablelist[info->parsedsourcenum]), NULL, M_DL_Notification);
if (dl)
{
dl->user_num = info->parsedsourcenum;
@ -1027,11 +1339,43 @@ void M_Download_UpdateStatus(struct menu_s *m)
}
}
#include "fs.h"
static int QDECL MD_ExtractFiles(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath)
{ //this is gonna suck. threading would help, but gah.
package_t *p = parm;
flocation_t loc;
if (spath->FindFile(spath, &loc, fname, NULL) && loc.len < 0x80000000u)
{
char *f = malloc(loc.len);
const char *n;
if (f)
{
spath->ReadFile(spath, &loc, f);
if (*p->gamedir)
n = va("%s/%s", p->gamedir, fname);
else
n = fname;
FS_WriteFile(n, f, loc.len, p->fsroot);
free(f);
//keep track of the installed files, so we can delete them properly after.
MD_AddDep(p, DEP_FILE, fname);
}
}
return 1;
}
static void Menu_Download_Got(struct dl_download *dl)
{
qboolean successful = dl->status == DL_FINISHED;
char ext[8];
package_t *p;
char *tempname = dl->user_ctx;
for (p = availablepackages; p ; p=p->next)
{
if (p->download == dl)
break;
}
if (dl->file)
{
@ -1039,46 +1383,75 @@ static void Menu_Download_Got(struct dl_download *dl)
dl->file = NULL;
}
for (p = availablepackages; p ; p=p->next)
{
if (p->download == dl)
if (p)
{
char ext[8];
char *destname;
char *tempname;
struct packagedep_s *dep;
p->download = NULL;
if (!successful)
{
Con_Printf("Couldn't download %s (from %s to %s)\n", p->name, dl->url, p->dest);
if (*p->gamedir)
destname = va("%s/%s", p->gamedir, p->dest);
else
destname = va("%s", p->dest);
tempname = va("%s.tmp", destname);
Con_Printf("Couldn't download %s (from %s)\n", p->name, dl->url);
FS_Remove (tempname, p->fsroot);
Z_Free(tempname);
MD_StartADownload();
return;
}
COM_FileExtension(p->dest, ext, sizeof(ext));
if (p->extract == EXTRACT_ZIP)
{
vfsfile_t *f = FS_OpenVFS(tempname, "rb", p->fsroot);
if (f)
{
searchpathfuncs_t *archive = FSZIP_LoadArchive(f, tempname, NULL);
if (archive)
{
archive->EnumerateFiles(archive, "*", MD_ExtractFiles, p);
archive->ClosePath(archive);
p->flags |= DPF_HAVEAVERSION;
WriteInstalledPackages();
if (!stricmp(ext, "pak") || !stricmp(ext, "pk3"))
FS_ReloadPackFiles();
}
else
VFS_CLOSE(f);
}
FS_Remove (tempname, FS_GAMEONLY);
Z_Free(tempname);
MD_StartADownload();
return;
}
else
{
for (dep = p->deps; dep; dep = dep->next)
{
if (dep->dtype != DEP_FILE)
continue;
COM_FileExtension(dep->name, ext, sizeof(ext));
if (!stricmp(ext, "pak") || !stricmp(ext, "pk3"))
FS_UnloadPackFiles(); //we reload them after
if (*p->gamedir)
destname = va("%s/%s", p->gamedir, p->dest);
destname = va("%s/%s", p->gamedir, dep->name);
else
destname = va("%s", p->dest);
tempname = va("%s.tmp", destname);
destname = dep->name;
if (FS_Remove(destname, p->fsroot))
;
if (!FS_Rename2(tempname, destname, p->fsroot, p->fsroot))
{
Con_Printf("Couldn't rename %s to %s. Removed instead.\n", tempname, destname);
FS_Remove (tempname, p->fsroot);
Z_Free(tempname);
MD_StartADownload();
return;
}
Z_Free(tempname);
Con_Printf("Downloaded %s (to %s)\n", p->name, destname);
p->flags |= DPF_HAVEAVERSION;
WriteInstalledPackages();
@ -1090,10 +1463,13 @@ static void Menu_Download_Got(struct dl_download *dl)
return;
}
}
Con_Printf("menu_download: %s has no filename info\n", p->name);
}
else
Con_Printf("menu_download: Can't figure out where %s came from (url: %s)\n", dl->localname, dl->url);
FS_Remove (dl->localname, FS_GAMEONLY);
FS_Remove (tempname, FS_GAMEONLY);
Z_Free(tempname);
MD_StartADownload();
}

View file

@ -163,6 +163,7 @@ cvar_t r_stainfadetime = SCVAR ("r_stainfadetime", "1");
cvar_t r_stains = CVARFC("r_stains", IFMINIMAL("0","0.75"),
CVAR_ARCHIVE,
Cvar_Limiter_ZeroToOne_Callback);
cvar_t r_renderscale = CVARD("r_renderscale", "1", "Provides a way to enable subsampling or super-sampling");
cvar_t r_fxaa = CVARD("r_fxaa", "0", "Runs a post-procesing pass to strip the jaggies.");
cvar_t r_postprocshader = CVARD("r_postprocshader", "", "Specifies a custom shader to use as a post-processing shader");
cvar_t r_wallcolour = CVARAF ("r_wallcolour", "128 128 128",
@ -425,8 +426,9 @@ cvar_t r_fog_exp2 = CVARD ("r_fog_exp2", "1", "Expresses how fog fades wit
#ifdef VKQUAKE
cvar_t vk_stagingbuffers = CVARD ("vk_stagingbuffers", "", "Configures which dynamic buffers are copied into gpu memory for rendering, instead of reading from shared memory. Empty for default settings.\nAccepted chars are u, e, v, 0.");
cvar_t vk_submissionthread = CVARD ("vk_submissionthread", "1", "Execute submits+presents on a thread dedicated to executing them. This may be a significant speedup on certain drivers.");
cvar_t vk_submissionthread = CVARD ("vk_submissionthread", "", "Execute submits+presents on a thread dedicated to executing them. This may be a significant speedup on certain drivers.");
cvar_t vk_debug = CVARD ("vk_debug", "0", "Register a debug handler to display driver/layer messages. 2 enables the standard validation layers.");
cvar_t vk_loadglsl = CVARD ("vk_loadglsl", "", "Enable direct loading of glsl, where supported by drivers. Do not use in combination with vk_debug 2 (vk_debug should be 1 if you want to see any errors). Don't forget to do a vid_restart after.");
#endif
extern cvar_t gl_dither;
@ -461,9 +463,6 @@ void GLRenderer_Init(void)
Cvar_Register (&gl_finish, GLRENDEREROPTIONS);
Cvar_Register (&gl_lateswap, GLRENDEREROPTIONS);
Cvar_Register (&gl_lerpimages, GLRENDEREROPTIONS);
Cvar_Register (&r_postprocshader, GLRENDEREROPTIONS);
Cvar_Register (&r_fxaa, GLRENDEREROPTIONS);
Cvar_Register (&r_renderscale, GLRENDEREROPTIONS);
Cvar_Register (&dpcompat_psa_ungroup, GLRENDEREROPTIONS);
Cvar_Register (&r_lerpmuzzlehack, GLRENDEREROPTIONS);
@ -742,6 +741,9 @@ void Renderer_Init(void)
Cvar_Register (&r_wireframe, GRAPHICALNICETIES);
Cvar_Register (&r_wireframe_smooth, GRAPHICALNICETIES);
Cvar_Register (&r_refract_fbo, GRAPHICALNICETIES);
Cvar_Register (&r_postprocshader, GRAPHICALNICETIES);
Cvar_Register (&r_fxaa, GRAPHICALNICETIES);
Cvar_Register (&r_renderscale, GRAPHICALNICETIES);
Cvar_Register (&r_stereo_separation, GRAPHICALNICETIES);
Cvar_Register (&r_stereo_convergence, GRAPHICALNICETIES);
Cvar_Register (&r_stereo_method, GRAPHICALNICETIES);
@ -855,6 +857,7 @@ void Renderer_Init(void)
Cvar_Register (&vk_stagingbuffers, VKRENDEREROPTIONS);
Cvar_Register (&vk_submissionthread, VKRENDEREROPTIONS);
Cvar_Register (&vk_debug, VKRENDEREROPTIONS);
Cvar_Register (&vk_loadglsl, VKRENDEREROPTIONS);
#endif
// misc

View file

@ -311,7 +311,7 @@ static cvar_t s_al_debug = CVAR("s_al_debug", "0");
static cvar_t s_al_use_reverb = CVAR("s_al_use_reverb", "1");
static cvar_t s_al_max_distance = CVARFC("s_al_max_distance", "1000",0,OnChangeALSettings);
static cvar_t s_al_speedofsound = CVARFC("s_al_speedofsound", "343.3",0,OnChangeALSettings);
static cvar_t s_al_dopplerfactor = CVARFC("s_al_dopplerfactor", "3.0",0,OnChangeALSettings);
static cvar_t s_al_dopplerfactor = CVARFC("s_al_dopplerfactor", "1.0",0,OnChangeALSettings);
static cvar_t s_al_distancemodel = CVARFC("s_al_distancemodel", "2",0,OnChangeALSettings);
static cvar_t s_al_rolloff_factor = CVAR("s_al_rolloff_factor", "1");
static cvar_t s_al_reference_distance = CVAR("s_al_reference_distance", "120");
@ -504,7 +504,13 @@ static void OpenAL_ListenerUpdate(soundcardinfo_t *sc, int entnum, vec3_t origin
{
oalinfo_t *oali = sc->handle;
VectorScale(velocity, (snd_doppler.value?snd_doppler.value:s_al_velocityscale.value)/35.0, oali->ListenVel);
if (snd_doppler.modified)
{
snd_doppler.modified = false;
OnChangeALSettings(NULL,NULL);
}
VectorScale(velocity, s_al_velocityscale.value/35.0, oali->ListenVel);
VectorCopy(origin, oali->ListenPos);
oali->ListenEnt = entnum;
@ -994,7 +1000,7 @@ static void QDECL OnChangeALSettings (cvar_t *var, char *value)
palSpeedOfSound(s_al_speedofsound.value);
if (palDopplerFactor)
palDopplerFactor(s_al_dopplerfactor.value);
palDopplerFactor(s_al_dopplerfactor.value * snd_doppler.value);
if (palDistanceModel)
{

View file

@ -120,7 +120,7 @@ cvar_t snd_doppler_min = CVARAFD( "s_doppler_min", "0.5",
"snd_doppler_min", CVAR_ARCHIVE,
"Slowest allowed doppler scale.");
cvar_t snd_doppler_max = CVARAFD( "s_doppler_max", "2",
"snd_doppler", CVAR_ARCHIVE,
"snd_doppler_max", CVAR_ARCHIVE,
"Highest allowed doppler scale, to avoid things getting too weird.");
cvar_t snd_playbackrate = CVARFD( "snd_playbackrate", "1", CVAR_CHEAT, "Debugging cvar that changes the playback rate of all new sounds.");

View file

@ -76,10 +76,10 @@ typedef struct
qboolean isminimized; //can omit rendering as it won't be seen anyway.
int fullbright; // index of first fullbright color
unsigned fbvwidth; /*virtual 2d width*/
unsigned fbvwidth; /*virtual 2d width of the current framebuffer image*/
unsigned fbvheight; /*virtual 2d height*/
unsigned fbpwidth; /*virtual 2d width*/
unsigned fbpheight; /*virtual 2d height*/
unsigned fbpwidth; /*physical 2d width of the current framebuffer image*/
unsigned fbpheight; /*physical 2d height*/
struct image_s *framebuffer; /*the framebuffer fbo (set by democapture)*/
unsigned width; /*virtual 2d screen width*/

View file

@ -536,10 +536,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#elif defined(_WIN32)
#if defined(WINRT)
#define PLATFORM "WinRT" /*those poor poor souls. maybe just maybe I'll actually get the tools for a port, its just a shame that I won't be able to release said port*/
#elif defined(__amd64__)
#define PLATFORM "Win64"
#else
#define PLATFORM "Win32"
#define PLATFORM "Win"
#endif
#define ARCH_DL_POSTFIX ".dll"
#elif defined(_WIN16)
@ -551,11 +549,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#elif defined(ANDROID) || defined(__ANDROID__)
#define PLATFORM "Android" /*technically also linux*/
#elif defined(__linux__)
#if defined(__amd64__)
#define PLATFORM "Linux64"
#else
#define PLATFORM "Linux"
#endif
#elif defined(__APPLE__)
#include "TargetConditionals.h"
#if TARGET_IPHONE_SIMULATOR
@ -602,6 +596,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define ARCH_CPU_POSTFIX "x86"
#elif defined(__powerpc__) || defined(__ppc__)
#define ARCH_CPU_POSTFIX "ppc"
#elif defined(__aarch64__)
#define ARCH_CPU_POSTFIX "arm64"
#elif defined(__arm__)
#define ARCH_CPU_POSTFIX "arm"
#else

View file

@ -82,6 +82,7 @@ anyway, the actual interface is the same. the old version might be slower, but w
#include <features.h> /* for glibc version */
#if defined(__GLIBC__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 14)
__asm__(".symver memcpy,memcpy@GLIBC_2.2.5");
__asm__(".symver memmove,memmove@GLIBC_2.2.5");
#endif
#endif
/*end glibc workaround*/

View file

@ -247,7 +247,6 @@ void Con_SetActive (console_t *con);
qboolean Con_NameForNum(int num, char *buffer, int buffersize);
console_t *Con_FindConsole(const char *name);
console_t *Con_Create(const char *name, unsigned int flags);
void Con_SetVisible (console_t *con);
void Con_PrintCon (console_t *con, const char *txt, unsigned int parseflags);
qboolean Con_InsertConChars (console_t *con, conline_t *line, int offset, conchar_t *c, int len);
conline_t *Con_ResizeLineBuffer(console_t *con, conline_t *old, unsigned int length);

View file

@ -2907,7 +2907,7 @@ const gamemode_info_t gamemode_info[] = {
//for quake, we also allow extracting all files from paks. some people think it loads faster that way or something.
//cmdline switch exename protocol name(dpmaster) identifying file exec dir1 dir2 dir3 dir(fte) full name
{"-quake", "q1", MASTER_PREFIX"Quake", {"id1/pak0.pak", "id1/quake.rc"},QCFG, {"id1", "qw", "*fte"}, "Quake", "https://fte.triptohell.info/downloadables.txt" /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
{"-quake", "q1", MASTER_PREFIX"Quake", {"id1/pak0.pak", "id1/quake.rc"},QCFG, {"id1", "qw", "*fte"}, "Quake", "https://fte.triptohell.info/downloadables.php" /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/},
//quake's mission packs should not be favoured over the base game nor autodetected
//third part mods also tend to depend upon the mission packs for their huds, even if they don't use any other content.
//and q2 also has a rogue/pak0.pak file that we don't want to find and cause quake2 to look like dissolution of eternity

View file

@ -43,7 +43,7 @@ extern ID3D11Device *pD3DDev11;
STDMETHOD_(SIZE_T, GetBufferSize)(THIS) PURE;
};
#undef INTERFACE
/*
#define D3D11_SHADER_VARIABLE_DESC void
typedef unsigned int D3D_SHADER_INPUT_TYPE;
typedef unsigned int D3D_RESOURCE_RETURN_TYPE;
@ -101,16 +101,17 @@ extern ID3D11Device *pD3DDev11;
};
#define ID3D11ShaderReflection_GetVariableByName(r,v) r->lpVtbl->GetVariableByName(r,v)
#undef INTERFACE
*/
#else
#include <d3d11shader.h>
#endif
//const GUID IID_ID3D11ShaderReflection = {0x8d536ca1, 0x0cca, 0x4956, {0xa8, 0x37, 0x78, 0x69, 0x63, 0x75, 0x55, 0x84}};
const GUID IID_ID3D11ShaderReflection = {0x0a233719, 0x3960, 0x4578, {0x9d, 0x7c, 0x20, 0x3b, 0x8b, 0x1d, 0x9c, 0xc1}};
//const GUID IID_ID3D11ShaderReflection = {0x0a233719, 0x3960, 0x4578, {0x9d, 0x7c, 0x20, 0x3b, 0x8b, 0x1d, 0x9c, 0xc1}};
#define ID3DBlob_GetBufferPointer(b) b->lpVtbl->GetBufferPointer(b)
#define ID3DBlob_Release(b) b->lpVtbl->Release(b)
#define ID3DBlob_GetBufferSize(b) b->lpVtbl->GetBufferSize(b)
#define ID3D11ShaderReflection_Release IUnknown_Release
//#define ID3D11ShaderReflection_Release IUnknown_Release
HRESULT (WINAPI *pD3DCompile) (
LPCVOID pSrcData,
@ -126,13 +127,6 @@ HRESULT (WINAPI *pD3DCompile) (
ID3DBlob **ppErrorMsgs
);
HRESULT (WINAPI *pD3DReflect)(
LPCVOID pSrcData,
SIZE_T SrcDataSize,
REFIID pInterface,
void **ppReflector
);
static dllhandle_t *shaderlib;
@ -148,7 +142,7 @@ HRESULT STDMETHODCALLTYPE d3dinclude_Open(ID3DInclude *this, D3D_INCLUDE_TYPE In
{
if (IncludeType == D3D_INCLUDE_SYSTEM)
{
if (!strcmp(pFileName, "ftedefs.h"))
if (!strcmp(pFileName, "ftedefs.h") || !strcmp(pFileName, "sys/defs.h"))
{
static const char *defstruct =
"cbuffer ftemodeldefs : register(b0)\n"
@ -189,6 +183,7 @@ HRESULT STDMETHODCALLTYPE d3dinclude_Open(ID3DInclude *this, D3D_INCLUDE_TYPE In
*pBytes = strlen(*ppData);
return S_OK;
}
//fog
}
else
{
@ -406,31 +401,6 @@ static qboolean D3D11Shader_LoadBlob(program_t *prog, const char *name, unsigned
qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *hull, const char *domain, const char *geom, const char *frag, qboolean silenterrors, vfsfile_t *blobfile)
{
static const char *defaultsamplers[] =
{
"s_shadowmap",
"s_projectionmap",
"s_diffuse",
"s_normalmap",
"s_specular",
"s_upper",
"s_lower",
"s_fullbright",
"s_paletted",
"s_reflectcube",
"s_reflectmask",
"s_lightmap",
"s_deluxmap"
#if MAXRLIGHTMAPS > 1
,"s_lightmap1"
,"s_lightmap2"
,"s_lightmap3"
,"s_deluxmap1"
,"s_deluxmap2"
,"s_deluxmap3"
#endif
};
char *vsformat;
char *hsformat = NULL;
char *dsformat = NULL;
@ -439,8 +409,8 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned
D3D_SHADER_MACRO defines[64];
ID3DBlob *vcode = NULL, *hcode = NULL, *dcode = NULL, *gcode = NULL, *fcode = NULL, *errors = NULL;
qboolean success = false;
ID3D11ShaderReflection *freflect;
int i;
// ID3D11ShaderReflection *freflect;
// int i;
if (d3dfeaturelevel >= D3D_FEATURE_LEVEL_11_0) //and 11.1
{
@ -653,7 +623,7 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned
}
if (fcode)
/* if (fcode)
{
pD3DReflect(ID3DBlob_GetBufferPointer(fcode), ID3DBlob_GetBufferSize(fcode), &IID_ID3D11ShaderReflection, (void**)&freflect);
if (freflect)
@ -667,11 +637,11 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned
}
tmu = prog->numsamplers;
for (i = 0; i < sizeof(defaultsamplers)/sizeof(defaultsamplers[0]); i++)
for (i = 0; sh_defaultsamplers[i]; i++)
{
// if (prog->defaulttextures & (1u<<i))
// continue;
if (SUCCEEDED(freflect->lpVtbl->GetResourceBindingDescByName(freflect, va("t%s", defaultsamplers[i]+1), &bdesc)))
if (SUCCEEDED(freflect->lpVtbl->GetResourceBindingDescByName(freflect, va("t%s", sh_defaultsamplers[i]+1), &bdesc)))
prog->defaulttextures |= (1u<<i);
if (!(prog->defaulttextures & (1u<<i)))
continue;
@ -682,7 +652,7 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned
else
Con_Printf("%s: D3DReflect failed, unable to get reflection info\n", name);
}
*/
if (vcode)
ID3DBlob_Release(vcode);
if (hcode)
@ -704,13 +674,11 @@ qboolean D3D11Shader_Init(unsigned int flevel)
dllfunction_t funcsold[] =
{
{(void**)&pD3DCompile, "D3DCompileFromMemory"},
{(void**)&pD3DReflect, "D3DReflect"},
{NULL,NULL}
};
dllfunction_t funcsnew[] =
{
{(void**)&pD3DCompile, "D3DCompile"},
{(void**)&pD3DReflect, "D3DReflect"},
{NULL,NULL}
};

View file

@ -260,30 +260,6 @@ static void D3D9Shader_ProgAutoFields(program_t *prog, const char *progname, cva
unsigned int i, p;
int uniformloc;
static const char *defaultsamplers[] =
{
"s_shadowmap",
"s_projectionmap",
"s_diffuse",
"s_normalmap",
"s_specular",
"s_upper",
"s_lower",
"s_fullbright",
"s_paletted",
"s_reflectcube",
"s_reflectmask",
"s_lightmap",
"s_deluxmap"
#if MAXRLIGHTMAPS > 1
,"s_lightmap1"
,"s_lightmap2"
,"s_lightmap3"
,"s_deluxmap1"
,"s_deluxmap2"
,"s_deluxmap3"
#endif
};
#define ALTLIGHTMAPSAMP 13
#define ALTDELUXMAPSAMP 16
@ -364,12 +340,12 @@ static void D3D9Shader_ProgAutoFields(program_t *prog, const char *progname, cva
}
}
for (i = 0; i < sizeof(defaultsamplers)/sizeof(defaultsamplers[0]); i++)
for (i = 0; sh_defaultsamplers[i]; i++)
{
//figure out which ones are needed.
if (prog->defaulttextures & (1u<<i))
continue; //don't spam
uniformloc = D3D9Shader_FindUniform(&pp->h, 2, defaultsamplers[i]);
uniformloc = D3D9Shader_FindUniform(&pp->h, 2, sh_defaultsamplers[i]);
if (uniformloc != -1)
prog->defaulttextures |= (1u<<i);
}
@ -390,11 +366,11 @@ static void D3D9Shader_ProgAutoFields(program_t *prog, const char *progname, cva
if (!prog->permu[p].h.loaded)
continue;
sampnum = prog->numsamplers;
for (i = 0; i < sizeof(defaultsamplers)/sizeof(defaultsamplers[0]); i++)
for (i = 0; sh_defaultsamplers[i]; i++)
{
if (prog->defaulttextures & (1u<<i))
{
uniformloc = D3D9Shader_FindUniform(&prog->permu[p].h, 2, defaultsamplers[i]);
uniformloc = D3D9Shader_FindUniform(&prog->permu[p].h, 2, sh_defaultsamplers[i]);
if (uniformloc != -1)
{
int v[4] = {sampnum};

View file

@ -1237,6 +1237,8 @@ static qboolean (D3D11_SCR_UpdateScreen) (void)
scr_drawloading = true;
SCR_DrawLoading (true);
scr_drawloading = false;
if (R2D_Flush)
R2D_Flush();
// IDirect3DDevice9_EndScene(pD3DDev9);
D3D11_PresentOrCrash();
return true;

View file

@ -26,10 +26,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "httpserver", "..\http\https
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftequake", "ftequake.vcproj", "{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}"
ProjectSection(ProjectDependencies) = postProject
{E6CDA919-628B-45BF-A5DB-FB55179D6443} = {E6CDA919-628B-45BF-A5DB-FB55179D6443}
{9767E236-8454-44E9-8999-CD5BDAFBE9BA} = {9767E236-8454-44E9-8999-CD5BDAFBE9BA}
{0018E098-B12A-4E4D-9B22-6772DA287080} = {0018E098-B12A-4E4D-9B22-6772DA287080}
{6ABD62A3-C5A0-43E8-BA4F-84606057774F} = {6ABD62A3-C5A0-43E8-BA4F-84606057774F}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dedserver", "dedserver.vcproj", "{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}"
@ -43,8 +40,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "irc", "..\..\plugins\irc\ir
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "private", "..\..\plugins\private\private.vcproj", "{74542CA7-48C1-4664-9007-66F751131EA3}"
ProjectSection(ProjectDependencies) = postProject
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364} = {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}
{72269FEE-293D-40BC-A7AE-E429F4496869} = {72269FEE-293D-40BC-A7AE-E429F4496869}
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364} = {88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "targets", "targets", "{EB5DFF7C-C0A8-426C-BC66-524162350F1B}"

View file

@ -3569,7 +3569,7 @@ void GLBE_SelectMode(backendmode_t mode)
if (!shaderstate.allblackshader.glsl.handle)
{
const char *defs[] = {NULL};
shaderstate.allblackshader = GLSlang_CreateProgram("allblackprogram", gl_config_gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
shaderstate.allblackshader = GLSlang_CreateProgram(NULL, "allblackprogram", gl_config_gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
shaderstate.allblack_mvp = qglGetUniformLocationARB(shaderstate.allblackshader.glsl.handle, "m_modelviewprojection");
}
/*BEM_DEPTHONLY does support mesh writing, but its not the only way its used... FIXME!*/
@ -3594,7 +3594,7 @@ void GLBE_SelectMode(backendmode_t mode)
if (gl_config_nofixedfunc && !shaderstate.allblackshader.glsl.handle)
{
const char *defs[] = {NULL};
shaderstate.allblackshader = GLSlang_CreateProgram("allblackprogram", gl_config_gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
shaderstate.allblackshader = GLSlang_CreateProgram(NULL, "allblackprogram", gl_config_gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
shaderstate.allblack_mvp = qglGetUniformLocationARB(shaderstate.allblackshader.glsl.handle, "m_modelviewprojection");
}
@ -4147,7 +4147,7 @@ static void DrawMeshes(void)
if (!shaderstate.allblackshader.glsl.handle)
{
const char *defs[] = {NULL};
shaderstate.allblackshader = GLSlang_CreateProgram("allblackprogram", gl_config_gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
shaderstate.allblackshader = GLSlang_CreateProgram(NULL, "allblackprogram", gl_config_gles?100:110, defs, "#include \"sys/skeletal.h\"\nvoid main(){gl_Position = skeletaltransform();}", NULL, NULL, NULL, "void main(){gl_FragColor=vec4(0.0,0.0,0.0,1.0);}", false, NULL);
shaderstate.allblack_mvp = qglGetUniformLocationARB(shaderstate.allblackshader.glsl.handle, "m_modelviewprojection");
}

View file

@ -53,7 +53,6 @@ extern cvar_t gl_part_flame;
extern cvar_t r_bloom;
extern cvar_t r_wireframe_smooth;
cvar_t r_renderscale = CVARD("r_renderscale", "1", "Provides a way to enable subsampling or super-sampling");
cvar_t gl_affinemodels = SCVAR("gl_affinemodels","0");
cvar_t gl_finish = SCVAR("gl_finish","0");
cvar_t gl_dither = SCVAR("gl_dither", "1");

View file

@ -1028,6 +1028,32 @@ static qboolean Shader_ParseProgramCvar(char *script, cvar_t **cvarrefs, char **
}
#endif
const char *sh_defaultsamplers[] =
{
"s_shadowmap",
"s_projectionmap",
"s_diffuse",
"s_normalmap",
"s_specular",
"s_upper",
"s_lower",
"s_fullbright",
"s_paletted",
"s_reflectcube",
"s_reflectmask",
"s_lightmap",
"s_deluxmap",
#if MAXRLIGHTMAPS > 1
"s_lightmap1",
"s_lightmap2",
"s_lightmap3",
"s_deluxmap1",
"s_deluxmap2",
"s_deluxmap3",
#endif
NULL
};
/*program text is already loaded, this function parses the 'header' of it to see which permutations it provides, and how many times we need to recompile it*/
static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *script, int qrtype, int ver, char *blobfilename)
{
@ -1067,14 +1093,18 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
extern cvar_t gl_specular;
#endif
#ifdef VKQUAKE
if (qrenderer == QR_VULKAN && (qrtype == QR_VULKAN || qrtype == QR_OPENGL))
{
if (qrtype == QR_VULKAN && VK_LoadBlob(prog, script, name))
return true;
}
else
#endif
if (qrenderer != qrtype)
{
return false;
}
#ifdef VKQUAKE
if (qrenderer == QR_VULKAN)
return VK_LoadBlob(prog, script, name);
#endif
#if defined(GLQUAKE) || defined(D3DQUAKE)
ver = 0;
@ -1106,6 +1136,37 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
tess = true;
script += 6;
}
else if (!strncmp(script, "!!samps", 7))
{
script += 7;
while (*script != '\n' && *script != '\r')
{
int i;
char *start;
while (*script == ' ' || *script == '\t')
script++;
start = script;
while (*script != ' ' && *script != '\t' && *script != '\r' && *script != '\n')
script++;
for (i = 0; sh_defaultsamplers[i]; i++)
{
if (!strncmp(start, sh_defaultsamplers[i]+2, script-start) && sh_defaultsamplers[i][2+script-start] == 0)
{
prog->defaulttextures |= (1u<<i);
break;
}
}
if (!sh_defaultsamplers[i])
{
i = atoi(start);
if (i)
prog->numsamplers = i;
else
Con_Printf("Unknown texture name in %s\n", name);
}
}
}
else if (!strncmp(script, "!!cvardf", 8))
{
script += 8;
@ -1593,12 +1654,12 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype)
*h = '\0';
if (strchr(basicname, '/') || strchr(basicname, '.'))
{
{ //explicit path
FS_LoadFile(basicname, &file);
*blobname = 0;
}
else
{
{ //renderer-specific files
if (sh_config.progpath)
{
Q_snprintfz(blobname, sizeof(blobname), sh_config.progpath, basicname);
@ -4867,7 +4928,7 @@ void Shader_DefaultBSPLM(const char *shortname, shader_t *s, const void *args)
}
}
#endif
if (!builtin && ((sh_config.progs_supported && qrenderer == QR_OPENGL) || sh_config.progs_required || qrenderer == QR_VULKAN))
if (!builtin && ((sh_config.progs_supported && qrenderer == QR_OPENGL) || sh_config.progs_required))
{
builtin = (
"{\n"

View file

@ -1237,6 +1237,7 @@ static const char *glsl_hdrs[] =
"attribute vec4 v_colour4;\n"
#endif
"#endif\n"
#ifndef NOLEGACY
"uniform sampler2D s_shadowmap;\n"
"uniform samplerCube s_projectionmap;\n"
"uniform sampler2D s_diffuse;\n"
@ -1259,6 +1260,7 @@ static const char *glsl_hdrs[] =
"uniform sampler2D s_deluxmap1;\n"
"uniform sampler2D s_deluxmap2;\n"
"uniform sampler2D s_deluxmap3;\n"
#endif
#endif
"#ifdef USEUBOS\n"
@ -1822,7 +1824,7 @@ qboolean GLSlang_GenerateIncludes(int maxstrings, int *strings, const GLchar *pr
// glslang helper api function definitions
// type should be GL_FRAGMENT_SHADER_ARB or GL_VERTEX_SHADER_ARB
//doesn't check to see if it was okay. use FinishShader for that.
static GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char **precompilerconstants, const char *shadersource, GLenum shadertype, qboolean silent)
static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int ver, const char **precompilerconstants, const char *shadersource, GLenum shadertype, qboolean silent)
{
GLhandleARB shader;
int i;
@ -1888,6 +1890,61 @@ static GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char *
length[strings] = strlen(prstrings[strings]);
strings++;
}
if (prog)
{ //for compat with vulkan, that injects samplers...
const char *numberedsamplernames[] =
{
"uniform sampler2D s_t0;\n",
"uniform sampler2D s_t1;\n",
"uniform sampler2D s_t2;\n",
"uniform sampler2D s_t3;\n",
"uniform sampler2D s_t4;\n",
"uniform sampler2D s_t5;\n",
"uniform sampler2D s_t6;\n",
"uniform sampler2D s_t7;\n",
};
#ifdef NOLEGACY
const char *defaultsamplernames[] =
{
"uniform sampler2D s_shadowmap;\n",
"uniform samplerCube s_projectionmap;\n",
"uniform sampler2D s_diffuse;\n",
"uniform sampler2D s_normalmap;\n",
"uniform sampler2D s_specular;\n",
"uniform sampler2D s_upper;\n",
"uniform sampler2D s_lower;\n",
"uniform sampler2D s_fullbright;\n",
"uniform sampler2D s_paletted;\n",
"uniform samplerCube s_reflectcube;\n",
"uniform sampler2D s_reflectmask;\n",
"uniform sampler2D s_lightmap;\n#define s_lightmap0 s_lightmap\n",
"uniform sampler2D s_deluxmap;\n#define s_deluxmap0 s_deluxmap\n",
"uniform sampler2D s_lightmap1;\n",
"uniform sampler2D s_lightmap2;\n",
"uniform sampler2D s_lightmap3;\n",
"uniform sampler2D s_deluxmap1;\n",
"uniform sampler2D s_deluxmap2;\n",
"uniform sampler2D s_deluxmap3;\n",
};
for (i = 0; i < countof(defaultsamplernames); i++)
{
if (prog->defaulttextures & (1u<<i))
{
prstrings[strings] = defaultsamplernames[i];
length[strings] = strlen(prstrings[strings]);
strings++;
}
}
#endif
for (i = 0; i < prog->numsamplers && i < countof(numberedsamplernames); i++)
{
prstrings[strings] = numberedsamplernames[i];
length[strings] = strlen(prstrings[strings]);
strings++;
}
}
break;
case GL_GEOMETRY_SHADER_ARB:
prstrings[strings] = "#define GEOMETRY_SHADER\n";
@ -2199,7 +2256,7 @@ qboolean GLSlang_ValidateProgram(union programhandle_u *h, const char *name, qbo
return true;
}
union programhandle_u GLSlang_CreateProgram(const char *name, int ver, const char **precompilerconstants, const char *vert, const char *cont, const char *eval, const char *geom, const char *frag, qboolean silent, vfsfile_t *blobfile)
union programhandle_u GLSlang_CreateProgram(program_t *prog, const char *name, int ver, const char **precompilerconstants, const char *vert, const char *cont, const char *eval, const char *geom, const char *frag, qboolean silent, vfsfile_t *blobfile)
{
union programhandle_u ret;
GLhandleARB vs;
@ -2227,11 +2284,11 @@ union programhandle_u GLSlang_CreateProgram(const char *name, int ver, const cha
if (!precompilerconstants)
precompilerconstants = &nullconstants;
fs = GLSlang_CreateShader(name, ver, precompilerconstants, frag, GL_FRAGMENT_SHADER_ARB, silent);
gs = GLSlang_CreateShader(name, ver, precompilerconstants, geom, GL_GEOMETRY_SHADER_ARB, silent);
vs = GLSlang_CreateShader(name, ver, precompilerconstants, vert, GL_VERTEX_SHADER_ARB, silent);
cs = GLSlang_CreateShader(name, ver, precompilerconstants, cont, GL_TESS_CONTROL_SHADER_ARB, silent);
es = GLSlang_CreateShader(name, ver, precompilerconstants, eval, GL_TESS_EVALUATION_SHADER_ARB, silent);
fs = GLSlang_CreateShader(prog, name, ver, precompilerconstants, frag, GL_FRAGMENT_SHADER_ARB, silent);
gs = GLSlang_CreateShader(prog, name, ver, precompilerconstants, geom, GL_GEOMETRY_SHADER_ARB, silent);
vs = GLSlang_CreateShader(prog, name, ver, precompilerconstants, vert, GL_VERTEX_SHADER_ARB, silent);
cs = GLSlang_CreateShader(prog, name, ver, precompilerconstants, cont, GL_TESS_CONTROL_SHADER_ARB, silent);
es = GLSlang_CreateShader(prog, name, ver, precompilerconstants, eval, GL_TESS_EVALUATION_SHADER_ARB, silent);
fs = GLSlang_FinishShader(fs, name, GL_FRAGMENT_SHADER_ARB, silent);
gs = GLSlang_FinishShader(gs, name, GL_GEOMETRY_SHADER_ARB, silent);
@ -2307,7 +2364,7 @@ qboolean GLSlang_CreateProgramPermu(program_t *prog, const char *name, unsigned
return false; //can happen in gles2
#endif
prog->permu[permu].h = GLSlang_CreateProgram(name, ver, precompilerconstants, vert, tcs, tes, geom, frag, noerrors, blobfile);
prog->permu[permu].h = GLSlang_CreateProgram(prog, name, ver, precompilerconstants, vert, tcs, tes, geom, frag, noerrors, blobfile);
if (prog->permu[permu].h.glsl.handle)
return true;
return false;
@ -2369,30 +2426,6 @@ static void GLSlang_DeleteProg(program_t *prog)
static void GLSlang_ProgAutoFields(program_t *prog, const char *progname, cvar_t **cvars, char **cvarnames, int *cvartypes)
{
static const char *defaultsamplers[] =
{
"s_shadowmap",
"s_projectionmap",
"s_diffuse",
"s_normalmap",
"s_specular",
"s_upper",
"s_lower",
"s_fullbright",
"s_paletted",
"s_reflectcube",
"s_reflectmask",
"s_lightmap",
"s_deluxmap"
#if MAXRLIGHTMAPS > 1
,"s_lightmap1"
,"s_lightmap2"
,"s_lightmap3"
,"s_deluxmap1"
,"s_deluxmap2"
,"s_deluxmap3"
#endif
};
#define ALTLIGHTMAPSAMP 13
#define ALTDELUXMAPSAMP 16
@ -2485,12 +2518,12 @@ static void GLSlang_ProgAutoFields(program_t *prog, const char *progname, cvar_t
prog->numsamplers = i+1;
}
}
for (i = 0; i < sizeof(defaultsamplers)/sizeof(defaultsamplers[0]); i++)
for (i = 0; sh_defaultsamplers[i]; i++)
{
//figure out which ones are needed.
if (prog->defaulttextures & (1u<<i))
continue; //don't spam
uniformloc = qglGetUniformLocationARB(pp->h.glsl.handle, defaultsamplers[i]);
uniformloc = qglGetUniformLocationARB(pp->h.glsl.handle, sh_defaultsamplers[i]);
if (uniformloc != -1)
prog->defaulttextures |= (1u<<i);
}
@ -2512,11 +2545,11 @@ static void GLSlang_ProgAutoFields(program_t *prog, const char *progname, cvar_t
continue;
sampnum = prog->numsamplers;
GLSlang_UseProgram(prog->permu[p].h.glsl.handle);
for (i = 0; i < sizeof(defaultsamplers)/sizeof(defaultsamplers[0]); i++)
for (i = 0; sh_defaultsamplers[i]; i++)
{
if (prog->defaulttextures & (1u<<i))
{
uniformloc = qglGetUniformLocationARB(prog->permu[p].h.glsl.handle, defaultsamplers[i]);
uniformloc = qglGetUniformLocationARB(prog->permu[p].h.glsl.handle, sh_defaultsamplers[i]);
if (uniformloc != -1)
qglUniform1iARB(uniformloc, sampnum);
sampnum++;

View file

@ -1078,7 +1078,8 @@ extern void (APIENTRY *qglBindVertexArray)(GLuint vaoarray);
//glslang helper api
union programhandle_u GLSlang_CreateProgram(const char *name, int ver, const char **precompilerconstants, const char *vert, const char *cont, const char *eval, const char *geom, const char *frag, qboolean silent, vfsfile_t *blobfile);
struct programshared_s;
union programhandle_u GLSlang_CreateProgram(struct programshared_s *prog, const char *name, int ver, const char **precompilerconstants, const char *vert, const char *cont, const char *eval, const char *geom, const char *frag, qboolean silent, vfsfile_t *blobfile);
GLint GLSlang_GetUniformLocation (int prog, char *name);
void GL_SelectProgram(int program);
#define GLSlang_UseProgram(prog) GL_SelectProgram(prog)
@ -1087,7 +1088,7 @@ void GL_SelectProgram(int program);
#ifdef _DEBUG
#ifdef __GNUC__
#if defined(__GNUC__) && !defined(NACL)
#define checkglerror() do {int i=qglGetError(); if (i) Sys_Printf("GL Error %i detected at line %s:%i (caller %p)\n", i, __FILE__, __LINE__, __builtin_return_address(0));}while(0)
#else
#define checkglerror() do {int i=qglGetError(); if (i) Con_Printf("GL Error %i detected at line %s:%i\n", i, __FILE__, __LINE__);}while(0)

File diff suppressed because it is too large Load diff

View file

@ -713,6 +713,7 @@ typedef struct
} sh_config_t;
extern sh_config_t sh_config;
#endif
extern const char *sh_defaultsamplers[];
#ifdef GLSLONLY
#define gl_config_nofixedfunc true

View file

@ -1735,7 +1735,7 @@ void PDECL PR_ExecuteProgram (pubprogfuncs_t *ppf, func_t fnum)
{
// if (pr_global_struct->self)
// ED_Print (PROG_TO_EDICT(pr_global_struct->self));
#if defined(__GNUC__) && !defined(FTE_TARGET_WEB)
#if defined(__GNUC__) && !defined(FTE_TARGET_WEB) && !defined(NACL)
printf("PR_ExecuteProgram: NULL function from exe (address %p)\n", __builtin_return_address(0));
#else
printf("PR_ExecuteProgram: NULL function from exe\n");

View file

@ -11287,21 +11287,21 @@ void PR_DumpPlatform_f(void)
{"CONTENT_SKY", "const float", QW|NQ|CS, NULL, Q1CONTENTS_SKY},
{"CONTENT_LADDER", "const float", QW|NQ|CS, "If this value is assigned to a solid_bsp's .skin field, the entity will become a ladder volume.", Q1CONTENTS_LADDER},
{"CONTENTBIT_NONE", "const int", QW|NQ|CS, NULL, FTECONTENTS_EMPTY},
{"CONTENTBIT_SOLID", "const int", QW|NQ|CS, NULL, FTECONTENTS_SOLID},
{"CONTENTBIT_LAVA", "const int", QW|NQ|CS, NULL, FTECONTENTS_LAVA},
{"CONTENTBIT_SLIME", "const int", QW|NQ|CS, NULL, FTECONTENTS_SLIME},
{"CONTENTBIT_WATER", "const int", QW|NQ|CS, NULL, FTECONTENTS_WATER},
{"CONTENTBIT_FTELADDER", "const int", QW|NQ|CS, NULL, FTECONTENTS_LADDER},
{"CONTENTBIT_PLAYERCLIP", "const int", QW|NQ|CS, NULL, FTECONTENTS_PLAYERCLIP},
{"CONTENTBIT_MONSTERCLIP", "const int", QW|NQ|CS, NULL, FTECONTENTS_MONSTERCLIP},
{"CONTENTBIT_BODY", "const int", QW|NQ|CS, NULL, FTECONTENTS_BODY},
{"CONTENTBIT_CORPSE", "const int", QW|NQ|CS, NULL, FTECONTENTS_CORPSE},
{"CONTENTBIT_Q2LADDER", "const int", QW|NQ|CS, NULL, Q2CONTENTS_LADDER},
{"CONTENTBIT_SKY", "const int", QW|NQ|CS, NULL, FTECONTENTS_SKY},
{"CONTENTBITS_POINTSOLID", "const int", QW|NQ|CS, NULL, MASK_POINTSOLID},
{"CONTENTBITS_BOXSOLID", "const int", QW|NQ|CS, NULL, MASK_BOXSOLID},
{"CONTENTBITS_FLUID", "const int", QW|NQ|CS, NULL, FTECONTENTS_FLUID},
{"CONTENTBIT_NONE", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_EMPTY)},
{"CONTENTBIT_SOLID", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_SOLID)},
{"CONTENTBIT_LAVA", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_LAVA)},
{"CONTENTBIT_SLIME", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_SLIME)},
{"CONTENTBIT_WATER", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_WATER)},
{"CONTENTBIT_FTELADDER", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_LADDER)},
{"CONTENTBIT_PLAYERCLIP", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_PLAYERCLIP)},
{"CONTENTBIT_MONSTERCLIP", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_MONSTERCLIP)},
{"CONTENTBIT_BODY", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_BODY)},
{"CONTENTBIT_CORPSE", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_CORPSE)},
{"CONTENTBIT_Q2LADDER", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(Q2CONTENTS_LADDER)},
{"CONTENTBIT_SKY", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_SKY)},
{"CONTENTBITS_POINTSOLID", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(MASK_POINTSOLID)},
{"CONTENTBITS_BOXSOLID", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(MASK_BOXSOLID)},
{"CONTENTBITS_FLUID", "const int", QW|NQ|CS, NULL, 0,STRINGIFY(FTECONTENTS_FLUID)},
{"CHAN_AUTO", "const float", QW|NQ|CS, "The automatic channel, play as many sounds on this channel as you want, and they'll all play, however the other channels will replace each other.", CHAN_AUTO},
{"CHAN_WEAPON", "const float", QW|NQ|CS, NULL, CHAN_WEAPON},

View file

@ -95,6 +95,7 @@ void dumpprogblob(FILE *out, unsigned char *buf, unsigned int size)
struct blobheader
{
unsigned char blobmagic[4]; //\xffSPV
unsigned int blobversion;
unsigned int defaulttextures; //s_diffuse etc flags
unsigned int numtextures; //s_t0 count
@ -164,6 +165,7 @@ int generatevulkanblobs(struct blobheader *blob, size_t maxblobsize, char *fname
// snprintf(vertname, sizeof(vertname), "vulkan/%s.vert", fname);
// snprintf(fragname, sizeof(fragname), "vulkan/%s.frag", fname);
memcpy(blob->blobmagic, "\xffSPV", 4);
blob->blobversion = 1;
blob->defaulttextures = 0;
blob->numtextures = 0;
@ -332,7 +334,6 @@ int generatevulkanblobs(struct blobheader *blob, size_t maxblobsize, char *fname
};
int binding = 2;
inheader = 0;
printf("%s %u+%#x samplers\n", fname, blob->numtextures, blob->defaulttextures);
fprintf(temp, "#define OFFSETMAPPING (cvar_r_glsl_offsetmapping>0)\n");
fprintf(temp, "#define SPECULAR (cvar_gl_specular>0)\n");
fprintf(temp, "#ifdef FRAGMENT_SHADER\n");

View file

@ -1,3 +1,5 @@
!!samps 1
struct a2v
{
float4 pos: POSITION;

View file

@ -1,3 +1,5 @@
!!samps diffuse upper lower fullbright
struct a2v
{
float4 pos: POSITION;

View file

@ -1,3 +1,5 @@
!!samps diffuse fullbright
//regular sky shader for scrolling q1 skies
//the sky surfaces are thrown through this as-is.

View file

@ -1,3 +1,5 @@
!!samps diffuse
struct a2v
{
float4 pos: POSITION;

View file

@ -1,3 +1,5 @@
!!samps diffuse fullbright lightmap
struct a2v
{
float4 pos: POSITION;

View file

@ -1,3 +1,4 @@
!!samps diffuse
!!cvarf r_wateralpha
struct a2v

View file

@ -1,3 +1,5 @@
!!samps lightmap
struct a2v
{
float4 pos: POSITION;

View file

@ -1,3 +1,4 @@
!!samps 1
struct a2v
{
float4 pos: POSITION;

View file

@ -1,3 +1,4 @@
!!samps 1
!!cvard3 r_menutint=0.2 0.2 0.2
!!cvardf r_menutint_inverse=0.0

View file

@ -1,10 +1,11 @@
!!samps diffuse normalmap specular upper lower shadowmap projectionmap
!!permu BUMP
!!permu FRAMEBLEND
!!permu SKELETAL
!!permu UPPERLOWER
!!permu FOG
!!cvarf r_glsl_offsetmapping_scale
!!cvardf r_glsl_pcf
!!cvardf r_glsl_pcf=5
//this is the main shader responsible for realtime dlights.
@ -77,21 +78,21 @@ struct v2f
#ifdef FRAGMENT_SHADER
Texture2D t_diffuse : register(t0);
Texture2D t_normalmap : register(t1);
Texture2D t_specular : register(t2);
Texture2D t_upper : register(t3);
Texture2D t_lower : register(t4);
Texture2D t_shadowmap : register(t5);
TextureCube t_projectionmap : register(t6);
Texture2D t_shadowmap : register(t0);
TextureCube t_projectionmap : register(t1);
Texture2D t_diffuse : register(t2);
Texture2D t_normalmap : register(t3);
Texture2D t_specular : register(t4);
Texture2D t_upper : register(t5);
Texture2D t_lower : register(t6);
SamplerState s_diffuse : register(s0);
SamplerState s_normalmap : register(s1);
SamplerState s_specular : register(s2);
SamplerState s_upper : register(s3);
SamplerState s_lower : register(s4);
SamplerComparisonState s_shadowmap : register(s5);
SamplerState s_projectionmap : register(s6);
SamplerComparisonState s_shadowmap : register(s0);
SamplerState s_projectionmap : register(s1);
SamplerState s_diffuse : register(s2);
SamplerState s_normalmap : register(s3);
SamplerState s_specular : register(s4);
SamplerState s_upper : register(s5);
SamplerState s_lower : register(s6);
#ifdef PCF

View file

@ -994,6 +994,7 @@ qboolean SW_SCR_UpdateScreen(void)
SCR_DrawTwoDimensional(0, 0);
V_UpdatePalette (false);
return true;
}
void SW_VBO_Begin(vbobctx_t *ctx, size_t maxsize)

View file

@ -289,6 +289,7 @@ extern int be_maxpasses;
struct blobheader
{
unsigned char blobmagic[4];
unsigned int blobversion;
unsigned int defaulttextures; //s_diffuse etc flags
unsigned int numtextures; //s_t0 count
@ -404,97 +405,9 @@ static VkSampler VK_GetSampler(unsigned int flags)
}
#endif
qboolean VK_LoadBlob(program_t *prog, void *blobdata, const char *name)
//creates the layout stuff for the prog.
static VK_FinishProg(program_t *prog, const char *name)
{
//fixme: should validate that the offset+lengths are within the blobdata.
struct blobheader *blob = blobdata;
VkShaderModuleCreateInfo info = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO};
VkShaderModule vert, frag;
unsigned char *cvardata;
if (blob->blobversion != 1)
{
Con_Printf("Blob %s is outdated\n", name);
return false;
}
info.flags = 0;
info.codeSize = blob->vertlength;
info.pCode = (uint32_t*)((char*)blob+blob->vertoffset);
VkAssert(vkCreateShaderModule(vk.device, &info, vkallocationcb, &vert));
info.flags = 0;
info.codeSize = blob->fraglength;
info.pCode = (uint32_t*)((char*)blob+blob->fragoffset);
VkAssert(vkCreateShaderModule(vk.device, &info, vkallocationcb, &frag));
prog->vert = vert;
prog->frag = frag;
prog->nofixedcompat = true;
prog->numsamplers = blob->numtextures;
prog->defaulttextures = blob->defaulttextures;
prog->supportedpermutations = blob->permutations;
if (blob->cvarslength)
{
prog->cvardata = BZ_Malloc(blob->cvarslength);
prog->cvardatasize = blob->cvarslength;
memcpy(prog->cvardata, (char*)blob+blob->cvarsoffset, blob->cvarslength);
}
else
{
prog->cvardata = NULL;
prog->cvardatasize = 0;
}
//go through the cvars and a) validate them. b) create them with the right defaults.
//FIXME: validate
for (cvardata = prog->cvardata; cvardata < prog->cvardata + prog->cvardatasize; )
{
unsigned char type = cvardata[2], size = cvardata[3]-'0';
char *cvarname;
cvar_t *var;
cvardata += 4;
cvarname = cvardata;
cvardata += strlen(cvarname)+1;
if (type >= 'A' && type <= 'Z')
{ //args will be handled by the blob loader.
VK_ShaderReadArgument(name, cvarname, type, size, cvardata);
}
else
{
var = Cvar_FindVar(cvarname);
if (var)
var->flags |= CVAR_SHADERSYSTEM; //just in case
else
{
union
{
int i;
float f;
} u;
char value[128];
uint32_t i;
for (i = 0; i < size; i++)
{
u.i = (cvardata[i*4+0]<<24)|(cvardata[i*4+0]<<16)|(cvardata[i*4+0]<<8)|(cvardata[i*4+0]<<0);
if (i)
Q_strncatz(value, " ", sizeof(value));
if (type == 'i' || type == 'b')
Q_strncatz(value, va("%i", u.i), sizeof(value));
else
Q_strncatz(value, va("%f", u.f), sizeof(value));
}
Cvar_Get(cvarname, value, CVAR_SHADERSYSTEM, "GLSL Settings");
}
}
cvardata += 4*size;
}
{
VkDescriptorSetLayout desclayout;
VkDescriptorSetLayoutCreateInfo descSetLayoutCreateInfo = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO};
@ -561,6 +474,663 @@ qboolean VK_LoadBlob(program_t *prog, void *blobdata, const char *name)
VkAssert(vkCreatePipelineLayout(vk.device, &pipeLayoutCreateInfo, vkallocationcb, &layout));
prog->layout = layout;
}
}
static const char *vulkan_glsl_hdrs[] =
{
"sys/defs.h",
"#define DEFS_DEFINED\n"
"#undef texture2D\n" //nvidia is fucking us over
"#undef textureCube\n" //nvidia is fucking us over
"#define texture2D texture\n"
"#define textureCube texture\n"
"#define e_lmscale e_lmscales[0]\n"
,
"sys/skeletal.h",
"#ifdef SKELETAL\n"
"vec4 skeletaltransform()"
"{"
"mat3x4 wmat;\n"
"wmat = m_bones[int(v_bone.x)] * v_weight.x;\n"
"wmat += m_bones[int(v_bone.y)] * v_weight.y;\n"
"wmat += m_bones[int(v_bone.z)] * v_weight.z;\n"
"wmat += m_bones[int(v_bone.w)] * v_weight.w;\n"
"return m_modelviewprojection * vec4(vec4(v_position.xyz, 1.0) * wmat, 1.0);"
"}\n"
"vec4 skeletaltransform_nst(out vec3 n, out vec3 t, out vec3 b)"
"{"
"mat3x4 wmat;\n"
"wmat = m_bones[int(v_bone.x)] * v_weight.x;"
"wmat += m_bones[int(v_bone.y)] * v_weight.y;"
"wmat += m_bones[int(v_bone.z)] * v_weight.z;"
"wmat += m_bones[int(v_bone.w)] * v_weight.w;"
"n = vec4(v_normal.xyz, 0.0) * wmat;"
"t = vec4(v_svector.xyz, 0.0) * wmat;"
"b = vec4(v_tvector.xyz, 0.0) * wmat;"
"return m_modelviewprojection * vec4(vec4(v_position.xyz, 1.0) * wmat, 1.0);"
"}\n"
"vec4 skeletaltransform_wnst(out vec3 w, out vec3 n, out vec3 t, out vec3 b)"
"{"
"mat3x4 wmat;\n"
"wmat = m_bones[int(v_bone.x)] * v_weight.x;"
"wmat += m_bones[int(v_bone.y)] * v_weight.y;"
"wmat += m_bones[int(v_bone.z)] * v_weight.z;"
"wmat += m_bones[int(v_bone.w)] * v_weight.w;"
"n = vec4(v_normal.xyz, 0.0) * wmat;"
"t = vec4(v_svector.xyz, 0.0) * wmat;"
"b = vec4(v_tvector.xyz, 0.0) * wmat;"
"w = vec4(v_position.xyz, 1.0) * wmat;"
"return m_modelviewprojection * vec4(w, 1.0);"
"}\n"
"vec4 skeletaltransform_n(out vec3 n)"
"{"
"mat3x4 wmat;\n"
"wmat = m_bones[int(v_bone.x)] * v_weight.x;"
"wmat += m_bones[int(v_bone.y)] * v_weight.y;"
"wmat += m_bones[int(v_bone.z)] * v_weight.z;"
"wmat += m_bones[int(v_bone.w)] * v_weight.w;"
"n = vec4(v_normal.xyz, 0.0) * wmat;"
"return m_modelviewprojection * vec4(vec4(v_position.xyz, 1.0) * wmat, 1.0);"
"}\n"
"#else\n"
"#define skeletaltransform ftetransform\n"
"vec4 skeletaltransform_wnst(out vec3 w, out vec3 n, out vec3 t, out vec3 b)"
"{"
"n = v_normal;"
"t = v_svector;"
"b = v_tvector;"
"w = v_position.xyz;"
"return ftetransform();"
"}\n"
"vec4 skeletaltransform_nst(out vec3 n, out vec3 t, out vec3 b)"
"{"
"n = v_normal;"
"t = v_svector;"
"b = v_tvector;"
"return ftetransform();"
"}\n"
"vec4 skeletaltransform_n(out vec3 n)"
"{"
"n = v_normal;"
"return ftetransform();"
"}\n"
"#endif\n"
,
"sys/fog.h",
"#ifdef FRAGMENT_SHADER\n"
"#ifdef FOG\n"
"vec3 fog3(in vec3 regularcolour)"
"{"
"float z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w;\n"
"z = max(0.0,z-w_fogdepthbias);\n"
"#if #include \"cvar/r_fog_exp2\"\n"
"z *= z;\n"
"#endif\n"
"float fac = exp2(-(z * 1.442695));\n"
"fac = (1.0-w_fogalpha) + (clamp(fac, 0.0, 1.0)*w_fogalpha);\n"
"return mix(w_fogcolour, regularcolour, fac);\n"
"}\n"
"vec3 fog3additive(in vec3 regularcolour)"
"{"
"float z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w;\n"
"z = max(0.0,z-w_fogdepthbias);\n"
"#if #include \"cvar/r_fog_exp2\"\n"
"z *= z;\n"
"#endif\n"
"float fac = exp2(-(z * 1.442695));\n"
"fac = (1.0-w_fogalpha) + (clamp(fac, 0.0, 1.0)*w_fogalpha);\n"
"return regularcolour * fac;\n"
"}\n"
"vec4 fog4(in vec4 regularcolour)"
"{"
"return vec4(fog3(regularcolour.rgb), 1.0) * regularcolour.a;\n"
"}\n"
"vec4 fog4additive(in vec4 regularcolour)"
"{"
"float z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w;\n"
"z = max(0.0,z-w_fogdepthbias);\n"
"#if #include \"cvar/r_fog_exp2\"\n"
"z *= z;\n"
"#endif\n"
"float fac = exp2(-(z * 1.442695));\n"
"fac = (1.0-w_fogalpha) + (clamp(fac, 0.0, 1.0)*w_fogalpha);\n"
"return regularcolour * vec4(fac, fac, fac, 1.0);\n"
"}\n"
"vec4 fog4blend(in vec4 regularcolour)"
"{"
"float z = w_fogdensity * gl_FragCoord.z / gl_FragCoord.w;\n"
"z = max(0.0,z-w_fogdepthbias);\n"
"#if #include \"cvar/r_fog_exp2\"\n"
"z *= z;\n"
"#endif\n"
"float fac = exp2(-(z * 1.442695));\n"
"fac = (1.0-w_fogalpha) + (clamp(fac, 0.0, 1.0)*w_fogalpha);\n"
"return regularcolour * vec4(1.0, 1.0, 1.0, fac);\n"
"}\n"
"#else\n"
/*don't use macros for this - mesa bugs out*/
"vec3 fog3(in vec3 regularcolour) { return regularcolour; }\n"
"vec3 fog3additive(in vec3 regularcolour) { return regularcolour; }\n"
"vec4 fog4(in vec4 regularcolour) { return regularcolour; }\n"
"vec4 fog4additive(in vec4 regularcolour) { return regularcolour; }\n"
"vec4 fog4blend(in vec4 regularcolour) { return regularcolour; }\n"
"#endif\n"
"#endif\n"
,
"sys/offsetmapping.h",
"uniform float cvar_r_glsl_offsetmapping_scale;\n"
"vec2 offsetmap(sampler2D normtex, vec2 base, vec3 eyevector)\n"
"{\n"
"#if !defined(OFFSETMAPPING_SCALE)\n"
"#define OFFSETMAPPING_SCALE 1.0\n"
"#endif\n"
"#if defined(RELIEFMAPPING) && !defined(GL_ES)\n"
"float i, f;\n"
"vec3 OffsetVector = vec3(normalize(eyevector.xyz).xy * cvar_r_glsl_offsetmapping_scale * OFFSETMAPPING_SCALE * vec2(-1.0, 1.0), -1.0);\n"
"vec3 RT = vec3(vec2(base.xy"/* - OffsetVector.xy*OffsetMapping_Bias*/"), 1.0);\n"
"OffsetVector /= 10.0;\n"
"for(i = 1.0; i < 10.0; ++i)\n"
"RT += OffsetVector * step(texture2D(normtex, RT.xy).a, RT.z);\n"
"for(i = 0.0, f = 1.0; i < 5.0; ++i, f *= 0.5)\n"
"RT += OffsetVector * (step(texture2D(normtex, RT.xy).a, RT.z) * f - 0.5 * f);\n"
"return RT.xy;\n"
"#elif defined(OFFSETMAPPING)\n"
"vec2 OffsetVector = normalize(eyevector).xy * cvar_r_glsl_offsetmapping_scale * OFFSETMAPPING_SCALE * vec2(-1.0, 1.0);\n"
"vec2 tc = base;\n"
"tc += OffsetVector;\n"
"OffsetVector *= 0.333;\n"
"tc -= OffsetVector * texture2D(normtex, tc).w;\n"
"tc -= OffsetVector * texture2D(normtex, tc).w;\n"
"tc -= OffsetVector * texture2D(normtex, tc).w;\n"
"return tc;\n"
"#else\n"
"return base;\n"
"#endif\n"
"}\n"
,
"sys/pcf.h",
"#ifndef r_glsl_pcf\n"
"#define r_glsl_pcf 9\n"
"#endif\n"
"#if r_glsl_pcf < 1\n"
"#undef r_glsl_pcf\n"
"#define r_glsl_pcf 9\n"
"#endif\n"
"vec3 ShadowmapCoord(void)\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 ((vtexprojcoord.xyz-vec3(0.0,0.0,0.015))/vtexprojcoord.w + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5);\n"
//"#elif defined(CUBESHADOW)\n"
// vec3 shadowcoord = vshadowcoord.xyz / vshadowcoord.w;
// #define dosamp(x,y) shadowCube(s_t4, shadowcoord + vec2(x,y)*texscale.xy).r
"#else\n"
//figure out which axis to use
//texture is arranged thusly:
//forward left up
//back right down
"vec3 dir = abs(vtexprojcoord.xyz);\n"
//assume z is the major axis (ie: forward from the light)
"vec3 t = vtexprojcoord.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 = vtexprojcoord.zyx;\n"
"axis.x = 0.5;\n"
"}\n"
"if (dir.y > ma)\n"
"{\n"
"ma = dir.y;\n"
"t = vtexprojcoord.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(sampler2DShadow smap)\n"
"{\n"
"vec3 shadowcoord = ShadowmapCoord();\n"
"#if 0\n"//def GL_ARB_texture_gather
"vec2 ipart, fpart;\n"
"#define dosamp(x,y) textureGatherOffset(smap, 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
"mix(vec4(tl.rg, tr.rg), vec4(bl.ba, br.ba), fpart.y);\n" //top+bottom rows
"return dot(mix(col.rgb, col.agb, fpart.x), vec3(1.0/9.0));\n" //blend r+a, gb are mixed because its pretty much free and gives a nicer dot instruction instead of lots of adds.
"#else\n"
"#define dosamp(x,y) shadow2D(smap, shadowcoord.xyz + (vec3(x,y,0.0)*l_shadowmapscale.xyx)).r\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"
,
NULL
};
//glsl doesn't officially support #include, this might be vulkan, but don't push things.
qboolean Vulkan_GenerateIncludes(int maxstrings, int *strings, const char *prstrings[], int length[], const char *shadersource)
{
int i;
char *incline, *inc;
char incname[256];
while((incline=strstr(shadersource, "#include")))
{
if (*strings == maxstrings)
return false;
/*emit up to the include*/
if (incline - shadersource)
{
prstrings[*strings] = shadersource;
length[*strings] = incline - shadersource;
*strings += 1;
}
incline += 8;
incline = COM_ParseOut (incline, incname, sizeof(incname));
if (!strncmp(incname, "cvar/", 5))
{
cvar_t *var = Cvar_Get(incname+5, "0", 0, "shader cvars");
if (var)
{
var->flags |= CVAR_SHADERSYSTEM;
if (!Vulkan_GenerateIncludes(maxstrings, strings, prstrings, length, var->string))
return false;
}
else
{
/*dump something if the cvar doesn't exist*/
if (*strings == maxstrings)
return false;
prstrings[*strings] = "0";
length[*strings] = strlen("0");
*strings += 1;
}
}
else
{
for (i = 0; vulkan_glsl_hdrs[i]; i += 2)
{
if (!strcmp(incname, vulkan_glsl_hdrs[i]))
{
if (!Vulkan_GenerateIncludes(maxstrings, strings, prstrings, length, vulkan_glsl_hdrs[i+1]))
return false;
break;
}
}
if (!vulkan_glsl_hdrs[i])
{
if (FS_LoadFile(incname, (void**)&inc) != (qofs_t)-1)
{
if (!Vulkan_GenerateIncludes(maxstrings, strings, prstrings, length, inc))
{
FS_FreeFile(inc);
return false;
}
FS_FreeFile(inc);
}
}
}
/*move the pointer past the include*/
shadersource = incline;
}
if (*shadersource)
{
if (*strings == maxstrings)
return false;
/*dump the remaining shader string*/
prstrings[*strings] = shadersource;
length[*strings] = strlen(prstrings[*strings]);
*strings += 1;
}
return true;
}
//assumes VK_NV_glsl_shader for raw glsl
VkShaderModule VK_CreateGLSLModule(program_t *prog, const char *name, int ver, const char **precompilerconstants, const char *body, int isfrag)
{
VkShaderModuleCreateInfo info = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO};
VkShaderModule mod;
const char *strings[256];
int lengths[256];
unsigned int numstrings = 0;
char *blob;
size_t blobsize;
unsigned int i;
strings[numstrings++] = "#version 450 core\n";
strings[numstrings++] = "#define ENGINE_"DISTRIBUTION"\n";
strings[numstrings++] =
"layout(std140, binding=0) uniform entityblock"
"{\n"
"mat4 m_modelviewproj;"
"mat4 m_model;"
"mat4 m_modelinv;"
"vec3 e_eyepos;"
"float e_time;"
"vec3 e_light_ambient; float epad1;"
"vec3 e_light_dir; float epad2;"
"vec3 e_light_mul; float epad3;"
"vec4 e_lmscales[4];"
"vec3 e_uppercolour; float epad4;"
"vec3 e_lowercolour; float epad5;"
"vec4 e_colourident;"
"vec4 w_fogcolours;"
"float w_fogdensity; float w_fogdepthbias; vec2 epad6;"
"};\n"
"layout(std140, binding=1) uniform lightblock"
"{\n"
"mat4 l_cubematrix;"
"vec3 l_lightposition; float lpad1;"
"vec3 l_lightcolour; float lpad2;"
"vec3 l_lightcolourscale; float l_lightradius;"
"vec4 l_shadowmapproj;"
"vec2 l_shadowmapscale; vec2 lpad3;"
"};\n"
;
if (isfrag)
{
int bindloc = 0;
const char *bindlocations[] =
{
"layout(set=0, binding=2) ",
"layout(set=0, binding=3) ",
"layout(set=0, binding=4) ",
"layout(set=0, binding=5) ",
"layout(set=0, binding=6) ",
"layout(set=0, binding=7) ",
"layout(set=0, binding=8) ",
"layout(set=0, binding=9) ",
"layout(set=0, binding=10) ",
"layout(set=0, binding=11) ",
"layout(set=0, binding=12) ",
"layout(set=0, binding=13) ",
"layout(set=0, binding=14) ",
"layout(set=0, binding=15) ",
"layout(set=0, binding=16) ",
"layout(set=0, binding=17) ",
"layout(set=0, binding=18) ",
"layout(set=0, binding=19) ",
"layout(set=0, binding=20) ",
"layout(set=0, binding=21) ",
"layout(set=0, binding=22) ",
"layout(set=0, binding=23) ",
"layout(set=0, binding=24) ",
"layout(set=0, binding=25) ",
};
const char *numberedsamplernames[] =
{
"uniform sampler2D s_t0;\n",
"uniform sampler2D s_t1;\n",
"uniform sampler2D s_t2;\n",
"uniform sampler2D s_t3;\n",
"uniform sampler2D s_t4;\n",
"uniform sampler2D s_t5;\n",
"uniform sampler2D s_t6;\n",
"uniform sampler2D s_t7;\n",
};
const char *defaultsamplernames[] =
{
"uniform sampler2D s_shadowmap;\n",
"uniform samplerCube s_projectionmap;\n",
"uniform sampler2D s_diffuse;\n",
"uniform sampler2D s_normalmap;\n",
"uniform sampler2D s_specular;\n",
"uniform sampler2D s_upper;\n",
"uniform sampler2D s_lower;\n",
"uniform sampler2D s_fullbright;\n",
"uniform sampler2D s_paletted;\n",
"uniform samplerCube s_reflectcube;\n",
"uniform sampler2D s_reflectmask;\n",
"uniform sampler2D s_lightmap;\n#define s_lightmap0 s_lightmap\n",
"uniform sampler2D s_deluxmap;\n#define s_deluxmap0 s_deluxmap\n",
"uniform sampler2D s_lightmap1;\n",
"uniform sampler2D s_lightmap2;\n",
"uniform sampler2D s_lightmap3;\n",
"uniform sampler2D s_deluxmap1;\n",
"uniform sampler2D s_deluxmap2;\n",
"uniform sampler2D s_deluxmap3;\n",
};
strings[numstrings++] = "#define FRAGMENT_SHADER\n"
"#define varying in\n"
"layout(location=0) out vec4 outcolour;\n"
"#define gl_FragColor outcolour\n"
;
for (i = 0; i < countof(defaultsamplernames); i++)
{
if (prog->defaulttextures & (1u<<i))
{
strings[numstrings++] = bindlocations[bindloc++];
strings[numstrings++] = defaultsamplernames[i];
}
}
for (i = 0; i < prog->numsamplers && i < countof(numberedsamplernames); i++)
{
strings[numstrings++] = bindlocations[bindloc++];
strings[numstrings++] = numberedsamplernames[i];
}
}
else
{
strings[numstrings++] = "#define VERTEX_SHADER\n"
"#define attribute in\n"
"#define varying out\n"
"out gl_PerVertex"
"{"
"vec4 gl_Position;"
"};"
"layout(location=0) attribute vec3 v_position;"
"layout(location=1) attribute vec2 v_texcoord;"
"layout(location=2) attribute vec4 v_colour;"
"layout(location=3) attribute vec2 v_lmcoord;"
"layout(location=4) attribute vec3 v_normal;"
"layout(location=5) attribute vec3 v_svector;"
"layout(location=6) attribute vec3 v_tvector;"
//"layout(location=7) attribute vec4 v_boneweights;"
//"layout(location=8) attribute ivec4 v_bonenums;"
"\n"
"vec4 ftetransform()"
"{"
"vec4 proj = (m_modelviewproj*vec4(v_position,1.0));"
"proj.y *= -1;"
"proj.z = (proj.z + proj.w) / 2.0;"
"return proj;"
"}\n"
;
}
while (*precompilerconstants)
strings[numstrings++] = *precompilerconstants++;
for (i = 0, blobsize = 0; i < numstrings; i++)
lengths[i] = strlen(strings[i]);
Vulkan_GenerateIncludes(countof(strings), &numstrings, strings, lengths, body);
//now glue it all together into a single blob
for (i = 0, blobsize = 0; i < numstrings; i++)
blobsize += lengths[i];
blobsize++;
blob = malloc(blobsize);
for (i = 0, blobsize = 0; i < numstrings; i++)
{
memcpy(blob+blobsize, strings[i], lengths[i]);
blobsize += lengths[i];
}
blob[blobsize] = 0;
//and submit it.
info.flags = 0;
info.codeSize = blobsize;
info.pCode = (void*)blob;
VkAssert(vkCreateShaderModule(vk.device, &info, vkallocationcb, &mod));
return mod;
}
qboolean VK_LoadGLSL(program_t *prog, const char *name, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean noerrors, vfsfile_t *blobfile)
{
if (permu) //FIXME...
return false;
prog->pipelines = NULL;
prog->vert = VK_CreateGLSLModule(prog, name, ver, precompilerconstants, vert, false);
prog->frag = VK_CreateGLSLModule(prog, name, ver, precompilerconstants, frag, true);
VK_FinishProg(prog, name);
return true;
}
qboolean VK_LoadBlob(program_t *prog, void *blobdata, const char *name)
{
//fixme: should validate that the offset+lengths are within the blobdata.
struct blobheader *blob = blobdata;
VkShaderModuleCreateInfo info = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO};
VkShaderModule vert, frag;
unsigned char *cvardata;
if (blob->blobmagic[0] != 0xff || blob->blobmagic[1] != 'S' || blob->blobmagic[2] != 'P' || blob->blobmagic[3] != 'V')
return false; //assume its glsl. this is going to be 'fun'.
if (blob->blobversion != 1)
{
Con_Printf("Blob %s is outdated\n", name);
return false;
}
info.flags = 0;
info.codeSize = blob->vertlength;
info.pCode = (uint32_t*)((char*)blob+blob->vertoffset);
VkAssert(vkCreateShaderModule(vk.device, &info, vkallocationcb, &vert));
info.flags = 0;
info.codeSize = blob->fraglength;
info.pCode = (uint32_t*)((char*)blob+blob->fragoffset);
VkAssert(vkCreateShaderModule(vk.device, &info, vkallocationcb, &frag));
prog->vert = vert;
prog->frag = frag;
prog->nofixedcompat = true;
prog->numsamplers = blob->numtextures;
prog->defaulttextures = blob->defaulttextures;
prog->supportedpermutations = blob->permutations;
if (blob->cvarslength)
{
prog->cvardata = BZ_Malloc(blob->cvarslength);
prog->cvardatasize = blob->cvarslength;
memcpy(prog->cvardata, (char*)blob+blob->cvarsoffset, blob->cvarslength);
}
else
{
prog->cvardata = NULL;
prog->cvardatasize = 0;
}
//go through the cvars and a) validate them. b) create them with the right defaults.
//FIXME: validate
for (cvardata = prog->cvardata; cvardata < prog->cvardata + prog->cvardatasize; )
{
unsigned char type = cvardata[2], size = cvardata[3]-'0';
char *cvarname;
cvar_t *var;
cvardata += 4;
cvarname = cvardata;
cvardata += strlen(cvarname)+1;
if (type >= 'A' && type <= 'Z')
{ //args will be handled by the blob loader.
VK_ShaderReadArgument(name, cvarname, type, size, cvardata);
}
else
{
var = Cvar_FindVar(cvarname);
if (var)
var->flags |= CVAR_SHADERSYSTEM; //just in case
else
{
union
{
int i;
float f;
} u;
char value[128];
uint32_t i;
*value = 0;
for (i = 0; i < size; i++)
{
u.i = (cvardata[i*4+0]<<24)|(cvardata[i*4+1]<<16)|(cvardata[i*4+2]<<8)|(cvardata[i*4+3]<<0);
if (i)
Q_strncatz(value, " ", sizeof(value));
if (type == 'i' || type == 'b')
Q_strncatz(value, va("%i", u.i), sizeof(value));
else
Q_strncatz(value, va("%f", u.f), sizeof(value));
}
Cvar_Get(cvarname, value, CVAR_SHADERSYSTEM, "GLSL Settings");
}
}
cvardata += 4*size;
}
VK_FinishProg(prog, name);
prog->pipelines = NULL; //generated as needed, depending on blend states etc.
return true;
@ -574,6 +1144,7 @@ void VKBE_DeleteProg(program_t *prog)
pipe = prog->pipelines;
prog->pipelines = pipe->next;
if (pipe->pipeline)
vkDestroyPipeline(vk.device, pipe->pipeline, vkallocationcb);
Z_Free(pipe);
}
@ -2386,7 +2957,14 @@ static void BE_CreatePipeline(program_t *p, unsigned int shaderflags, unsigned i
err = vkCreateGraphicsPipelines(vk.device, vk.pipelinecache, 1, &pipeCreateInfo, vkallocationcb, &pipe->pipeline);
if (err)
{
shaderstate.activepipeline = VK_NULL_HANDLE;
if (err != VK_ERROR_INVALID_SHADER_NV)
Sys_Error("Error %i creating pipeline for %s. Check spir-v modules / drivers.\n", err, shaderstate.curshader->name);
else
Con_Printf("Error creating pipeline for %s. Check glsl / spir-v modules / drivers.\n", shaderstate.curshader->name);
return;
}
vkCmdBindPipeline(vk.frame->cbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, shaderstate.activepipeline=pipe->pipeline);
}
@ -2416,6 +2994,7 @@ static void BE_BindPipeline(program_t *p, unsigned int shaderflags, unsigned int
if (pipe->pipeline != shaderstate.activepipeline)
{
shaderstate.activepipeline = pipe->pipeline;
if (shaderstate.activepipeline)
vkCmdBindPipeline(vk.frame->cbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, shaderstate.activepipeline);
}
return;
@ -2460,9 +3039,11 @@ static void BE_SetupUBODescriptor(VkDescriptorSet set, VkWriteDescriptorSet *fir
desc->pTexelBufferView = NULL;
}
static void BE_RenderMeshProgram(program_t *p, shaderpass_t *pass, unsigned int shaderbits, unsigned int idxfirst, unsigned int idxcount)
static qboolean BE_SetupMeshProgram(program_t *p, shaderpass_t *pass, unsigned int shaderbits, unsigned int idxcount)
{
int perm = 0;
if (!p)
return false;
if (TEXLOADED(shaderstate.curtexnums->bump))
perm |= PERMUTATION_BUMPMAP;
@ -2477,6 +3058,8 @@ static void BE_RenderMeshProgram(program_t *p, shaderpass_t *pass, unsigned int
perm &= p->supportedpermutations;
BE_BindPipeline(p, shaderbits, VKBE_ApplyShaderBits(pass->shaderbits), perm);
if (!shaderstate.activepipeline)
return false; //err, something bad happened.
//most gpus will have a fairly low descriptor set limit of 4 (this is the minimum required)
//that isn't enough for all our textures, so we need to make stuff up as required.
@ -2567,6 +3150,8 @@ static void BE_RenderMeshProgram(program_t *p, shaderpass_t *pass, unsigned int
RQuantAdd(RQUANT_PRIMITIVEINDICIES, idxcount);
RQuantAdd(RQUANT_DRAWS, 1);
return true;
}
static void BE_DrawMeshChain_Internal(void)
@ -2933,7 +3518,7 @@ static void BE_DrawMeshChain_Internal(void)
}
vkCmdBindVertexBuffers(vk.frame->cbuf, 0, VK_BUFF_MAX, vertexbuffers, vertexoffsets);
BE_RenderMeshProgram(altshader->prog, altshader->passes, altshader->flags, idxfirst, idxcount);
if (BE_SetupMeshProgram(altshader->prog, altshader->passes, altshader->flags, idxcount))
vkCmdDrawIndexed(vk.frame->cbuf, idxcount, 1, idxfirst, 0, 0);
}
else if (1)
@ -2998,15 +3583,17 @@ static void BE_DrawMeshChain_Internal(void)
vertexoffsets[VK_BUFF_COL] = 0;
vkCmdBindVertexBuffers(vk.frame->cbuf, 0, VK_BUFF_MAX, vertexbuffers, vertexoffsets);
BE_RenderMeshProgram(shaderstate.programfixedemu[1], p, altshader->flags, idxfirst, idxcount);
if (BE_SetupMeshProgram(shaderstate.programfixedemu[1], p, altshader->flags, idxcount))
{
vkCmdPushConstants(vk.frame->cbuf, shaderstate.programfixedemu[1]->layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(passcolour), passcolour);
vkCmdDrawIndexed(vk.frame->cbuf, idxcount, 1, idxfirst, 0, 0);
}
}
else
{
BE_GenerateColourMods(vertcount, p, &vertexbuffers[VK_BUFF_COL], &vertexoffsets[VK_BUFF_COL]);
vkCmdBindVertexBuffers(vk.frame->cbuf, 0, VK_BUFF_MAX, vertexbuffers, vertexoffsets);
BE_RenderMeshProgram(shaderstate.programfixedemu[0], p, altshader->flags, idxfirst, idxcount);
if (BE_SetupMeshProgram(shaderstate.programfixedemu[0], p, altshader->flags, idxcount))
vkCmdDrawIndexed(vk.frame->cbuf, idxcount, 1, idxfirst, 0, 0);
}
}
@ -3060,8 +3647,11 @@ qboolean VKBE_SelectDLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], unsigned
{
lmode &= ~(LSHADER_SMAP|LSHADER_CUBE);
if (!VKBE_GenerateRTLightShader(lmode))
{
VKBE_SetupLightCBuffer(NULL, colour);
return false;
}
}
shaderstate.curdlight = dl;
shaderstate.curlmode = lmode;
@ -3835,10 +4425,13 @@ void VKBE_RT_Gen(struct vk_rendertarg *targ, uint32_t width, uint32_t height)
return; //no work to do.
if (targ->framebuffer)
{ //schedule the old one to be destroyed at the end of the current frame. DIE OLD ONE, DIE!
purge = VK_AtFrameEnd(VKBE_RT_Purge, sizeof(purge));
purge = VK_AtFrameEnd(VKBE_RT_Purge, sizeof(*purge));
purge->framebuffer = targ->framebuffer;
purge->colour = targ->colour;
purge->depth = targ->depth;
memset(&targ->colour, 0, sizeof(targ->colour));
memset(&targ->depth, 0, sizeof(targ->depth));
targ->framebuffer = VK_NULL_HANDLE;
}
targ->q_colour.vkimage = &targ->colour;
@ -4861,7 +5454,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);
BE_RenderMeshProgram(depthonlyshader->prog, depthonlyshader->passes, 0, 0, buf->numindicies);
if (BE_SetupMeshProgram(depthonlyshader->prog, depthonlyshader->passes, 0, buf->numindicies))
vkCmdDrawIndexed(vk.frame->cbuf, buf->numindicies, 1, 0, 0, 0);
}

View file

@ -8,6 +8,7 @@
extern qboolean vid_isfullscreen;
extern cvar_t vk_submissionthread;
extern cvar_t vk_debug;
extern cvar_t vk_loadglsl;
extern cvar_t vid_srgb, vid_vsync, vid_triplebuffer, r_stereo_method;
void R2D_Console_Resize(void);
@ -138,10 +139,13 @@ static void VK_DestroySwapChain(void)
{
uint32_t i;
if (vk.submitcondition)
{
Sys_LockConditional(vk.submitcondition);
vk.neednewswapchain = true;
Sys_ConditionSignal(vk.submitcondition);
Sys_UnlockConditional(vk.submitcondition);
}
if (vk.submitthread)
{
Sys_WaitOnThread(vk.submitthread);
@ -160,6 +164,7 @@ static void VK_DestroySwapChain(void)
VK_Submit_DoWork();
Sys_UnlockConditional(vk.submitcondition);
}
if (vk.device)
vkDeviceWaitIdle(vk.device);
VK_FencedCheck();
while(vk.frameendjobs)
@ -377,7 +382,7 @@ static qboolean VK_CreateSwapChain(void)
VkAssert(vkCreateFence(vk.device,&fci,vkallocationcb,&vk.acquirefences[i]));
}
/*-1 to hide any weird thread issues*/
while (vk.aquirelast < ACQUIRELIMIT-1 && vk.aquirelast < vk.backbuf_count && vk.aquirelast < 2 && vk.aquirelast <= vk.backbuf_count-surfcaps.minImageCount)
while (vk.aquirelast < ACQUIRELIMIT-1 && vk.aquirelast < vk.backbuf_count && vk.aquirelast <= vk.backbuf_count-surfcaps.minImageCount)
{
VkAssert(vkAcquireNextImageKHR(vk.device, vk.swapchain, UINT64_MAX, VK_NULL_HANDLE, vk.acquirefences[vk.aquirelast%ACQUIRELIMIT], &vk.acquirebufferidx[vk.aquirelast%ACQUIRELIMIT]));
vk.aquirelast++;
@ -805,7 +810,6 @@ void VK_FencedSync(void *work)
//the command buffer in question may even have not yet been submitted yet.
void *VK_AtFrameEnd(void (*passed)(void *work), size_t worksize)
{
//FIXME: OMG! BIG LEAK!
struct vk_fencework *w = Z_Malloc(worksize?worksize:sizeof(*w));
w->Passed = passed;
@ -1090,39 +1094,12 @@ void VK_R_DeInit (void)
void VK_SetupViewPortProjection(void)
{
extern cvar_t gl_mindist;
int x, x2, y2, y, w, h;
float fov_x, fov_y;
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
VectorCopy (r_refdef.vieworg, r_origin);
//
// set up viewpoint
//
x = r_refdef.vrect.x * vid.pixelwidth/(int)vid.width;
x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * vid.pixelwidth/(int)vid.width;
y = (r_refdef.vrect.y) * vid.pixelheight/(int)vid.height;
y2 = ((int)(r_refdef.vrect.y + r_refdef.vrect.height)) * vid.pixelheight/(int)vid.height;
// fudge around because of frac screen scale
if (x > 0)
x--;
if (x2 < vid.pixelwidth)
x2++;
if (y < 0)
y--;
if (y2 < vid.pixelheight)
y2++;
w = x2 - x;
h = y2 - y;
r_refdef.pxrect.x = x;
r_refdef.pxrect.y = y;
r_refdef.pxrect.width = w;
r_refdef.pxrect.height = h;
fov_x = r_refdef.fov_x;//+sin(cl.time)*5;
fov_y = r_refdef.fov_y;//-sin(cl.time+1)*5;
@ -1315,6 +1292,15 @@ void VK_Init_PostProc(void)
);
vk.scenepp_waterwarp->defaulttextures->upperoverlay = scenepp_texture_warp;
vk.scenepp_waterwarp->defaulttextures->loweroverlay = scenepp_texture_edge;
vk.scenepp_antialias = R_RegisterShader("fte_ppantialias", 0,
"{\n"
"program fxaa\n"
"{\n"
"map $sourcecolour\n"
"}\n"
"}\n"
);
}
@ -1322,6 +1308,10 @@ void VK_R_RenderView (void)
{
extern unsigned int r_viewcontents;
struct vk_rendertarg *rt;
extern cvar_t r_fxaa;
extern cvar_t r_renderscale, r_postprocshader;
float renderscale = r_renderscale.value;
shader_t *custompostproc;
if (r_norefresh.value || !vid.fbpwidth || !vid.fbpwidth)
{
@ -1357,12 +1347,59 @@ void VK_R_RenderView (void)
r_refdef.globalfog.density /= 64; //FIXME
}
VK_SetupViewPortProjection();
//FIXME: RDF_BLOOM|RDF_FISHEYE|RDF_CUSTOMPOSTPROC|RDF_ANTIALIAS|RDF_RENDERSCALE
if (r_refdef.flags & RDF_ALLPOSTPROC)
custompostproc = NULL;
if (!(r_refdef.flags & RDF_NOWORLDMODEL) && (*r_postprocshader.string))
{
custompostproc = R_RegisterCustom(r_postprocshader.string, SUF_NONE, NULL, NULL);
if (custompostproc)
r_refdef.flags |= RDF_CUSTOMPOSTPROC;
}
if (!(r_refdef.flags & RDF_NOWORLDMODEL) && r_fxaa.ival) //overlays will have problems.
r_refdef.flags |= RDF_ANTIALIAS;
//
// figure out the viewport
//
{
int x = r_refdef.vrect.x * vid.pixelwidth/(int)vid.width;
int x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * vid.pixelwidth/(int)vid.width;
int y = (r_refdef.vrect.y) * vid.pixelheight/(int)vid.height;
int y2 = ((int)(r_refdef.vrect.y + r_refdef.vrect.height)) * vid.pixelheight/(int)vid.height;
// fudge around because of frac screen scale
if (x > 0)
x--;
if (x2 < vid.pixelwidth)
x2++;
if (y < 0)
y--;
if (y2 < vid.pixelheight)
y2++;
r_refdef.pxrect.x = x;
r_refdef.pxrect.y = y;
r_refdef.pxrect.width = x2 - x;
r_refdef.pxrect.height = y2 - y;
}
if (renderscale != 1.0)
{
r_refdef.flags |= RDF_RENDERSCALE;
r_refdef.pxrect.width *= renderscale;
r_refdef.pxrect.height *= renderscale;
}
if (r_refdef.pxrect.width <= 0 || r_refdef.pxrect.height <= 0)
return; //you're not allowed to do that, dude.
//FIXME: RDF_BLOOM|RDF_FISHEYE
//FIXME: VF_RT_*
if (r_refdef.flags & (RDF_ALLPOSTPROC|RDF_RENDERSCALE))
{
r_refdef.pxrect.x = 0;
r_refdef.pxrect.y = 0;
rt = &postproc[postproc_buf++%countof(postproc)];
if (rt->width != r_refdef.pxrect.width || rt->height != r_refdef.pxrect.height)
VKBE_RT_Gen(rt, r_refdef.pxrect.width, r_refdef.pxrect.height);
@ -1371,39 +1408,8 @@ void VK_R_RenderView (void)
else
rt = NULL;
/*
{
VkClearDepthStencilValue val;
VkImageSubresourceRange range;
val.depth = 1;
val.stencil = 0;
range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
range.baseArrayLayer = 0;
range.baseMipLevel = 0;
range.layerCount = 1;
range.levelCount = 1;
vkCmdClearDepthStencilImage(vk.frame->cbuf, vk.depthbuf.image, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, &val, 1, &range);
}
*/
/*
vkCmdEndRenderPass(vk.frame->cbuf);
{
VkRenderPassBeginInfo rpiinfo = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO};
VkClearValue clearvalues[1];
clearvalues[0].depthStencil.depth = 1.0;
clearvalues[0].depthStencil.stencil = 0;
VK_SetupViewPortProjection();
rpiinfo.renderPass = vk.renderpass[1];
rpiinfo.renderArea.offset.x = r_refdef.pxrect.x;
rpiinfo.renderArea.offset.y = r_refdef.pxrect.y;
rpiinfo.renderArea.extent.width = r_refdef.pxrect.width;
rpiinfo.renderArea.extent.height = r_refdef.pxrect.height;
rpiinfo.framebuffer = vk.frame->backbuf->framebuffer;
rpiinfo.clearValueCount = 1;
rpiinfo.pClearValues = clearvalues;
vkCmdBeginRenderPass(vk.frame->cbuf, &rpiinfo, VK_SUBPASS_CONTENTS_INLINE);
}
*/
{
VkViewport vp[1];
VkRect2D scissor[1];
@ -1465,7 +1471,6 @@ void VK_R_RenderView (void)
r_refdef.flags &= ~RDF_WATERWARP;
VKBE_RT_End(); //WARNING: redundant begin+end renderpasses.
vk.sourcecolour = &rt->q_colour;
vk.sourcecolour = &rt->q_colour;
if (r_refdef.flags & RDF_ALLPOSTPROC)
{
rt = &postproc[postproc_buf++];
@ -1475,6 +1480,51 @@ void VK_R_RenderView (void)
R2D_Image(r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height, 0, 0, 1, 1, vk.scenepp_waterwarp);
R2D_Flush();
}
if (r_refdef.flags & RDF_CUSTOMPOSTPROC)
{
r_refdef.flags &= ~RDF_CUSTOMPOSTPROC;
VKBE_RT_End(); //WARNING: redundant begin+end renderpasses.
vk.sourcecolour = &rt->q_colour;
if (r_refdef.flags & RDF_ALLPOSTPROC)
{
rt = &postproc[postproc_buf++];
VKBE_RT_Begin(rt, 320, 240);
}
R2D_Image(r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height, 0, 1, 1, 0, custompostproc);
R2D_Flush();
}
if (r_refdef.flags & RDF_ANTIALIAS)
{
r_refdef.flags &= ~RDF_ANTIALIAS;
VKBE_RT_End(); //WARNING: redundant begin+end renderpasses.
vk.sourcecolour = &rt->q_colour;
if (r_refdef.flags & RDF_ALLPOSTPROC)
{
rt = &postproc[postproc_buf++];
VKBE_RT_Begin(rt, 320, 240);
}
R2D_Image(r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height, 0, 1, 1, 0, vk.scenepp_antialias);
R2D_Flush();
}
//FIXME: bloom
}
else if (r_refdef.flags & RDF_RENDERSCALE)
{
if (!vk.scenepp_rescale)
vk.scenepp_rescale = R_RegisterShader("fte_rescaler", 0,
"{\n"
"program default2d\n"
"{\n"
"map $sourcecolour\n"
"}\n"
"}\n"
);
VKBE_RT_End(); //WARNING: redundant begin+end renderpasses.
vk.sourcecolour = &rt->q_colour;
R2D_Image(r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height, 0, 0, 1, 1, vk.scenepp_rescale);
R2D_Flush();
}
vk.sourcecolour = r_nulltex;
@ -1741,12 +1791,11 @@ qboolean VK_SCR_GrabBackBuffer(void)
#ifdef THREADACQUIRE
while (vk.aquirenext == vk.aquirelast)
{ //we're still waiting for the render thread to increment acquirelast.
if (vk.vsync)
Sys_Sleep(0); //o.O
}
//wait for the queued acquire to actually finish
if (vk.vsync)
if (1)//vk.vsync)
{
//friendly wait
VkAssert(vkWaitForFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT], VK_FALSE, UINT64_MAX));
@ -1880,7 +1929,7 @@ qboolean VK_SCR_GrabBackBuffer(void)
if (r_clear.ival)
rpbi.renderPass = vk.renderpass[2];
else
rpbi.renderPass = vk.renderpass[1];
rpbi.renderPass = vk.renderpass[1]; //may still clear
rpbi.framebuffer = vk.frame->backbuf->framebuffer;
rpbi.renderArea.offset.x = 0;
rpbi.renderArea.offset.y = 0;
@ -1951,7 +2000,6 @@ void VK_DebugFramerate(void)
qboolean VK_SCR_UpdateScreen (void)
{
RSpeedLocals();
VkCommandBuffer bufs[1];
VK_FencedCheck();
@ -1991,7 +2039,7 @@ qboolean VK_SCR_UpdateScreen (void)
VK_CreateSwapChain();
vk.neednewswapchain = false;
if (vk_submissionthread.ival)
if (vk_submissionthread.ival || !*vk_submissionthread.string)
{
vk.submitthread = Sys_CreateThread("vksubmission", VK_Submit_Thread, NULL, THREADP_HIGHEST, 0);
}
@ -2031,11 +2079,7 @@ qboolean VK_SCR_UpdateScreen (void)
// vkCmdWriteTimestamp(vk.frame->cbuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, querypool, vk.bufferidx*2+1);
vkEndCommandBuffer(vk.frame->cbuf);
{
RSpeedRemark();
VKBE_FlushDynamicBuffers();
RSpeedEnd(RSPEED_SUBMIT);
}
bufs[0] = vk.frame->cbuf;
@ -2387,16 +2431,13 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat
VkResult err;
VkApplicationInfo app;
VkInstanceCreateInfo inst_info;
const char *extensions[] = { sysextname,
VK_KHR_SURFACE_EXTENSION_NAME,
VK_EXT_DEBUG_REPORT_EXTENSION_NAME
};
uint32_t extensions_count;
const char *extensions[8];
qboolean nvglsl = false;
uint32_t extensions_count = 0;
extensions[extensions_count++] = sysextname;
extensions[extensions_count++] = VK_KHR_SURFACE_EXTENSION_NAME;
if (vk_debug.ival)
extensions_count = 3;
else
extensions_count = 2;
extensions[extensions_count++] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
vk.neednewswapchain = true;
vk.triplebuffer = info->triplebuffer;
@ -2629,12 +2670,31 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat
}
}
{
const char *devextensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME};
uint32_t extcount = 0;
VkExtensionProperties *ext;
vkEnumerateDeviceExtensionProperties(vk.gpu, NULL, &extcount, NULL);
ext = malloc(sizeof(*ext)*extcount);
vkEnumerateDeviceExtensionProperties(vk.gpu, NULL, &extcount, ext);
while (extcount --> 0)
{
if (!strcmp(ext[extcount].extensionName, VK_NV_GLSL_SHADER_EXTENSION_NAME))
nvglsl = !!vk_loadglsl.ival;
}
free(ext);
}
{
const char *devextensions[8];
size_t numdevextensions = 0;
float queue_priorities[1] = {1.0};
VkDeviceQueueCreateInfo queueinf[2] = {{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO},{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO}};
VkDeviceCreateInfo devinf = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO};
devextensions[numdevextensions++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
if (nvglsl)
devextensions[numdevextensions++] = VK_NV_GLSL_SHADER_EXTENSION_NAME;
queueinf[0].pNext = NULL;
queueinf[0].queueFamilyIndex = vk.queueidx[0];
queueinf[0].queueCount = countof(queue_priorities);
@ -2648,7 +2708,7 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat
devinf.pQueueCreateInfos = queueinf;
devinf.enabledLayerCount = vklayercount;
devinf.ppEnabledLayerNames = vklayerlist;
devinf.enabledExtensionCount = countof(devextensions);
devinf.enabledExtensionCount = numdevextensions;
devinf.ppEnabledExtensionNames = devextensions;
devinf.pEnabledFeatures = NULL;
@ -2690,12 +2750,18 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat
}
sh_config.progpath = NULL;//"vulkan";
sh_config.progpath = NULL;
sh_config.blobpath = "spirv";
sh_config.shadernamefmt = NULL;//".spv";
if (nvglsl)
{
sh_config.progpath = "glsl/%s.glsl";
sh_config.shadernamefmt = "%s_glsl";
}
sh_config.progs_supported = true;
sh_config.progs_required = false;//true;
sh_config.progs_required = true;
sh_config.minver = -1;
sh_config.maxver = -1;
@ -2714,6 +2780,9 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat
sh_config.pDeleteProg = NULL;
sh_config.pLoadBlob = NULL;
if (nvglsl)
sh_config.pCreateProgram = VK_LoadGLSL;
else
sh_config.pCreateProgram = NULL;
sh_config.pValidateProgram = NULL;
sh_config.pProgAutoFields = NULL;
@ -2760,7 +2829,7 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat
{
vk.neednewswapchain = false;
if (vk_submissionthread.ival)
if (vk_submissionthread.ival || !*vk_submissionthread.string)
{
vk.submitthread = Sys_CreateThread("vksubmission", VK_Submit_Thread, NULL, THREADP_HIGHEST, 0);
}

View file

@ -40,6 +40,7 @@
//funcs specific to an instance
#define VKInst2Funcs \
VKFunc(EnumeratePhysicalDevices) \
VKFunc(EnumerateDeviceExtensionProperties) \
VKFunc(GetPhysicalDeviceProperties) \
VKFunc(GetPhysicalDeviceQueueFamilyProperties) \
VKFunc(GetPhysicalDeviceSurfaceSupportKHR) \
@ -314,6 +315,8 @@ extern struct vulkaninfo_s
texid_t sourcedepth;
shader_t *scenepp_waterwarp;
shader_t *scenepp_antialias;
shader_t *scenepp_rescale;
} vk;
struct pipeline_s
@ -333,6 +336,9 @@ qboolean VK_LoadTextureMips (texid_t tex, struct pendingtextureinfo *mips);
qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*createSurface)(void));
void VK_Shutdown(void);
struct programshared_s;
qboolean VK_LoadGLSL(struct programshared_s *prog, const char *name, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean noerrors, vfsfile_t *blobfile);
void VKBE_Init(void);
void VKBE_InitFramePools(struct vkframe *frame);
void VKBE_RestartFrame(void);

View file

@ -82,12 +82,13 @@ nonstatic void(mitem_desktop desktop) M_Main =
#endif
{menuitemtext_cladd16(m, _("Join Server"), "m_pop;m_servers", y); y += 16;}
if (assumetruecheckcommand("map")) {menuitemtext_cladd16(m, _("New Game"), "m_pop;m_newgame", y); y += 16;}
if (assumetruecheckcommand("menu_demo")) {menuitemtext_cladd16(m, _("Demos"), "m_pop;menu_demo", y); y += 16;}
if (assumefalsecheckcommand("menu_demo")) {menuitemtext_cladd16(m, _("Demos"), "m_pop;menu_demo", y); y += 16;}
if (assumetruecheckcommand("save") && (isserver()||dp_workarounds)) {menuitemtext_cladd16(m, _("Save"), "m_pop;m_save", y); y += 16;}
if (assumetruecheckcommand("load")) {menuitemtext_cladd16(m, _("Load"), "m_pop;m_load", y); y += 16;}
if (assumefalsecheckcommand("cef")) {menuitemtext_cladd16(m, _("Browser"), "m_pop;cef google.com", y); y += 16;}
if (assumefalsecheckcommand("xmpp")) {menuitemtext_cladd16(m, _("Social"), "m_pop;xmpp", y); y += 16;}
if (assumefalsecheckcommand("irc")) {menuitemtext_cladd16(m, _("IRC"), "m_pop;irc /info", y); y += 16;}
if (assumefalsecheckcommand("menu_download")) {menuitemtext_cladd16(m, _("Updates+Packages"), "m_pop;menu_download", y); y += 16;}
if (assumefalsecheckcommand("qi")) {menuitemtext_cladd16(m, _("Quake Injector"), "m_pop;qi", y); y += 16;}
{menuitemtext_cladd16(m, _("Options"), "m_pop;m_options", y); y += 16;}
{menuitemtext_cladd16(m, _("Quit"), "m_pop;m_quit", y); y += 16;}