smoother console scrolling (at least with the mouse)

support RLE+luminance+alpha tga files.
support half-float tga files.
recognise hdr astc images.
added appropriate fallbacks for astc support.
load mip-less .astc files (mostly just for debugging stuff).
allow packages to warn about required engine/gpu features.
catch when stdin flags get changed to blocking by external libraries, to avoid fatal stalls.
basic support for .mdx files (kingpin models)
sort packages loaded via wildcards, by datetime then name, to avoid random ordering from certain filesystems.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5531 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2019-09-04 08:32:22 +00:00
parent d561772bb0
commit 41b0d993f2
48 changed files with 5118 additions and 1466 deletions

View File

@ -93,7 +93,7 @@ cvar_t ignore_spec = CVAR("ignore_spec", "0");
cvar_t ignore_qizmo_spec = CVAR("ignore_qizmo_spec", "0");
cvar_t ignore_mode = CVAR("ignore_mode", "0");
cvar_t ignore_flood_duration = CVARD("ignore_flood_duration", "4", "Time limit for inbound messages to be considered duplicates.");
cvar_t ignore_flood = CVARD("ignore_flood", "0", "Provides a way to reduce inbound spam from flooding out your chat (dupe messages are ignored).\n0: No inbound flood protection.\n1: Duplicate non-team messages will be filtered.\n2: ALL duplicate messages will be filtered\n");
cvar_t ignore_flood = CVARD("ignore_flood", "0", "Provides a way to reduce inbound spam from flooding out your chat (dupe messages are ignored).\n0: No inbound flood protection.\n1: Duplicate non-team messages will be filtered.\n2: ALL duplicate messages will be filtered");
cvar_t ignore_opponents = CVAR("ignore_opponents", "0");
char ignoreteamlist[MAX_TEAMIGNORELIST][16 + 1];

View File

@ -3052,13 +3052,18 @@ void CL_ConnectionlessPacket (void)
Con_TPrintf ("redirect to %s\n", data);
if (NET_StringToAdr(data, PORT_DEFAULTSERVER, &adr))
{
data = "\xff\xff\xff\xffgetchallenge\n";
if (NET_CompareAdr(&connectinfo.adr, &net_from))
{
connectinfo.istransfer = true;
connectinfo.adr = adr;
NET_SendPacket (cls.sockets, strlen(data), data, &adr);
if (!NET_EnsureRoute(cls.sockets, "redir", cls.servername, &connectinfo.adr))
Con_Printf ("Unable to redirect to %s\n", data);
else
{
connectinfo.istransfer = true;
connectinfo.adr = adr;
data = "\xff\xff\xff\xffgetchallenge\n";
NET_SendPacket (cls.sockets, strlen(data), data, &adr);
}
}
}
return;

View File

@ -33,7 +33,7 @@ console_t *con_chat; // points to a chat console
#define Font_ScreenWidth() (vid.pixelwidth)
static int Con_DrawProgress(int left, int right, int y);
static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, int y, int top, int selactive, int selsx, int selex, int selsy, int seley, float lineagelimit);
static int Con_DrawConsoleLines(console_t *con, conline_t *l, float displayscroll, int sx, int ex, int y, int top, int selactive, int selsx, int selex, int selsy, int seley, float lineagelimit);
#ifdef QTERM
#include <windows.h>
@ -971,7 +971,7 @@ void Con_PrintCon (console_t *con, const char *txt, unsigned int parseflags)
con->current->newer = reuse;
con->current = reuse;
con->current->length = 0;
if (con->display == con->current->older)
if (con->display == con->current->older && con->displayscroll==0)
con->display = con->current;
break;
default:
@ -980,6 +980,8 @@ void Con_PrintCon (console_t *con, const char *txt, unsigned int parseflags)
con->current->length = 0;
con->cr = false;
}
if (!con->current->numlines)
con->current->numlines = 1;
if (!con->current->length && con_timestamps.ival && !(parseflags & PFS_CENTERED))
{
@ -1394,7 +1396,7 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y,
{
if (con->footerline)
{
y = Con_DrawConsoleLines(con, con->footerline, left, right, y, 0, selactive, selsx, selex, selsy, seley, 0);
y = Con_DrawConsoleLines(con, con->footerline, 0, left, right, y, 0, selactive, selsx, selex, selsy, seley, 0);
}
return y; //fixme: draw any unfinished lines of the current console instead.
}
@ -1553,7 +1555,7 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y,
/*if its getting completed to something, show some help about the command that is going to be used*/
if (con->footerline)
{
y = Con_DrawConsoleLines(con, con->footerline, left, right, y, 0, selactive, selsx, selex, selsy, seley, 0);
y = Con_DrawConsoleLines(con, con->footerline, 0, left, right, y, 0, selactive, selsx, selex, selsy, seley, 0);
}
/*just above that, we have the tab completion list*/
@ -1601,7 +1603,7 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y,
}
if (con->completionline->length)
y = Con_DrawConsoleLines(con, con->completionline, left, right, y, 0, selactive, selsx, selex, selsy, seley, 0);
y = Con_DrawConsoleLines(con, con->completionline, 0, left, right, y, 0, selactive, selsx, selex, selsy, seley, 0);
}
return y;
@ -2079,9 +2081,21 @@ int Con_DrawAlternateConsoles(int lines)
return y;
}
static void Con_DrawImageClip(float x, float y, float w, float h, float bottom, shader_t *pic)
{
if (bottom < y+h)
{
if (bottom <= y)
return;
R2D_Image(x,y,w,bottom-y,0,0,1,(bottom-y)/h,pic);
}
else
R2D_Image(x,y,w,h,0,0,1,1,pic);
}
//draws the conline_t list bottom-up within the width of the screen until the top of the screen is reached.
//if text is selected, the selstartline globals will be updated, so make sure the lines persist or check them.
static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, int y, int top, int selactive, int selsx, int selex, int selsy, int seley, float lineagelimit)
static int Con_DrawConsoleLines(console_t *con, conline_t *l, float displayscroll, int sx, int ex, int y, int top, int selactive, int selsx, int selex, int selsy, int seley, float lineagelimit)
{
int linecount;
conchar_t *starts[64], *ends[sizeof(starts)/sizeof(starts[0])];
@ -2090,17 +2104,28 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
int charh = Font_CharHeight();
unsigned int codeflags, codepoint;
float alphaval = 1;
float chop;
chop = displayscroll * Font_CharHeight();
if (l != con->completionline)
if (l != con->footerline)
if (l != con->current)
{
y -= 8;
y -= Font_CharHeight();
// draw arrows to show the buffer is backscrolled
for (x = sx ; x<ex; )
x = (Font_DrawChar (x, y, CON_WHITEMASK, '^')-x)*4+x;
if (chop)
{
y -= Font_CharHeight();
chop += 2*Font_CharHeight();
}
}
y += chop;
if (selactive != -1)
{
if (!selactive)
@ -2199,6 +2224,31 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
{
char *imgname;
linkinfo[linkinfolen] = 0;
imgname = Info_ValueForKey(linkinfo, "imgptr");
if (*imgname)
{
pic = R2D_SafeCachePic("tiprawimg");
pic->defaulttextures->base = Image_TextureIsValid(strtoull(imgname, NULL, 0));
if (pic && pic->defaulttextures->base)
{
if (!pic->defaulttextures->base->width || !pic->defaulttextures->base->height || !TEXLOADED(pic->defaulttextures->base))
picw = pich = 64;
else if (pic->defaulttextures->base->width > pic->defaulttextures->base->height)
{
picw = 64;
pich = (64.0*pic->defaulttextures->base->height)/pic->defaulttextures->base->width;
}
else
{
picw = (64.0*pic->defaulttextures->base->width)/pic->defaulttextures->base->height;
pich = 64;
}
break;
}
}
imgname = Info_ValueForKey(linkinfo, "img");
if (*imgname)
{
@ -2305,23 +2355,27 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
if (texth > pich)
{
texth = pich + (texth-pich)/2;
R2D_Image(sx*szx, (y-texth)*szy, picw*szx, pich*szy, 0, 0, 1, 1, pic);
Con_DrawImageClip(sx*szx, (y-texth)*szy, picw*szx, pich*szy, (y-chop+Font_CharHeight())*szy, pic);
pich = 0; //don't pad the text...
}
else
{
R2D_Image(sx*szx, (y-pich)*szy, picw*szx, pich*szy, 0, 0, 1, 1, pic);
Con_DrawImageClip(sx*szx, (y-pich)*szy, picw*szx, pich*szy, (y-chop+Font_CharHeight())*szy, pic);
pich -= texth;
y-= pich/2; //skip some space above and below the text block, to keep the text and image aligned.
if (chop)
chop -= pich/2;
}
if (R2D_Flush)
R2D_Flush();
// if (selsx < picw && selex < picw)
l->numlines = ceil((texth+pich)/Font_CharHeight());
}
l->numlines = linecount;
else
l->numlines = linecount;
while(linecount-- > 0)
{
@ -2330,6 +2384,15 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
y -= Font_CharHeight();
if (chop)
{
chop -= Font_CharHeight();
if (chop < 0)
chop = 0;
else
continue;
}
if (top && y < top)
break;
@ -2526,6 +2589,8 @@ static int Con_DrawConsoleLines(console_t *con, conline_t *l, int sx, int ex, in
break;
}
y -= pich/2;
if (chop)
chop -= pich/2;
if (y < top)
break;
}
@ -2799,7 +2864,7 @@ void Con_DrawConsole (int lines, qboolean noback)
l = con_current->display;
y = Con_DrawConsoleLines(con_current, l, sx, ex, y, top, selactive, selsx, selex, selsy, seley, 0);
y = Con_DrawConsoleLines(con_current, l, con_current->displayscroll, sx, ex, y, top, selactive, selsx, selex, selsy, seley, 0);
if (!haveprogress && lines == vid.height)
{
@ -3163,7 +3228,7 @@ void Con_DrawOneConsole(console_t *con, qboolean focused, struct font_s *font, f
if (!con->display)
con->display = con->current;
Con_DrawConsoleLines(con, con->display, x, sx, sy, y, selactive, selsx, selex, selsy, seley, lineagelimit);
Con_DrawConsoleLines(con, con->display, con->displayscroll, x, sx, sy, y, selactive, selsx, selex, selsy, seley, lineagelimit);
Font_EndString(font);
}

File diff suppressed because it is too large Load Diff

1567
engine/client/image_astc.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -673,8 +673,38 @@ qboolean Key_GetConsoleSelectionBox(console_t *con, int *sx, int *sy, int *ex, i
if (con->buttonsdown == CB_SCROLL || con->buttonsdown == CB_SCROLL_R)
{
float lineheight = Font_CharVHeight(font_console);
//left-mouse.
//scroll the console with the mouse. trigger links on release.
con->displayscroll += (con->mousecursor[1] - con->mousedown[1])/lineheight;
con->mousedown[1] = con->mousecursor[1];
while (con->displayscroll > con->display->numlines)
{
if (con->display->older)
{
con->displayscroll -= con->display->numlines;
con->display = con->display->older;
}
else
{
con->displayscroll = con->display->numlines;
break;
}
}
while (con->displayscroll <= 0)
{
if (con->display->newer)
{
con->display = con->display->newer;
con->displayscroll += con->display->numlines;
}
else
{
con->displayscroll = 0;
break;
}
}
/*
while (con->mousecursor[1] - con->mousedown[1] > 8 && con->display->older)
{
con->mousedown[1] += 8;
@ -685,7 +715,7 @@ qboolean Key_GetConsoleSelectionBox(console_t *con, int *sx, int *sy, int *ex, i
con->mousedown[1] -= 8;
con->display = con->display->newer;
}
*/
*sx = con->mousecursor[0];
*sy = con->mousecursor[1];
*ex = con->mousecursor[0];
@ -1585,12 +1615,26 @@ qboolean Key_EntryLine(console_t *con, unsigned char **line, int lineoffset, int
Sys_Clipboard_PasteText(CBT_SELECTION, Key_ConsolePaste, line);
return true;
}
if (((unicode=='V' || unicode=='v' || unicode==22) && ctrl) || (shift && key == K_INS))
if (((unicode=='V' || unicode=='v' || unicode==22/*sync*/) && ctrl) || (shift && key == K_INS))
{ //ctrl+v to paste from the windows-style clipboard.
Sys_Clipboard_PasteText(CBT_CLIPBOARD, Key_ConsolePaste, line);
return true;
}
if ((unicode=='X' || unicode=='x' || unicode==24/*cancel*/) && ctrl)
{ //cut - copy-to-clipboard-and-delete
Sys_SaveClipboard(CBT_CLIPBOARD, *line);
(*line)[lineoffset] = 0;
*linepos = strlen(*line);
return true;
}
if ((unicode=='U' || unicode=='u' || unicode==21/*nak*/) && ctrl)
{ //clear line
(*line)[lineoffset] = 0;
*linepos = strlen(*line);
return true;
}
if (unicode < ' ')
{
//if the user is entering control codes, then the ctrl+foo mechanism is probably unsupported by the unicode input stuff, so give best-effort replacements.
@ -1820,14 +1864,16 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode)
i = 8;
if (!con->display)
return true;
if (con->display == con->current)
i+=2; //skip over the blank input line, and extra so we actually move despite the addition of the ^^^^^ line
// if (con->display == con->current)
// i+=2; //skip over the blank input line, and extra so we actually move despite the addition of the ^^^^^ line
if (con->display->older != NULL)
{
while (i-->0)
con->displayscroll += i;
while (con->displayscroll >= con->display->numlines)
{
if (con->display->older == NULL)
break;
con->displayscroll -= con->display->numlines;
con->display = con->display->older;
con->display->time = realtime;
}
@ -1845,15 +1891,20 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode)
return true;
if (con->display->newer != NULL)
{
while (i-->0)
con->displayscroll -= i;
while (con->displayscroll < 0)
{
if (con->display->newer == NULL)
break;
con->display = con->display->newer;
con->display->time = realtime;
con->displayscroll += con->display->numlines;
}
if (con->display->newer && con->display->newer == con->current)
{
con->display = con->current;
con->displayscroll = 0;
}
return true;
}
}
@ -1862,6 +1913,7 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode)
{
if (con->display != con->oldest)
{
con->displayscroll = 0;
con->display = con->oldest;
return true;
}
@ -1871,6 +1923,7 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode)
{
if (con->display != con->current)
{
con->displayscroll = 0;
con->display = con->current;
return true;
}

View File

@ -2,6 +2,7 @@
//provides both a package manager and downloads menu.
//FIXME: block downloads of exe/dll/so/etc if not an https url (even if inside zips). also block such files from package lists over http.
#include "quakedef.h"
#include "shader.h"
#ifdef PACKAGEMANAGER
#if !defined(NOBUILTINMENUS) && !defined(SERVERONLY)
@ -161,15 +162,16 @@ typedef struct package_s {
struct packagedep_s *next;
enum
{
DEP_CONFLICT,
DEP_CONFLICT, //don't install if we have the named package installed.
DEP_FILECONFLICT, //don't install if this file already exists.
DEP_REQUIRE,
DEP_RECOMMEND, //like depend, but uninstalling will not bubble.
DEP_SUGGEST, //like recommend, but will not force install (ie: only prevents auto-uninstall)
DEP_REQUIRE, //don't install unless we have the named package installed.
DEP_RECOMMEND, //like depend, but uninstalling will not bubble.
DEP_SUGGEST, //like recommend, but will not force install (ie: only prevents auto-uninstall)
DEP_NEEDFEATURE, //requires a specific feature to be available (typically controlled via a cvar)
// DEP_MIRROR,
// DEP_FAILEDMIRROR,
DEP_FILE
DEP_FILE //a file that will be installed
} dtype;
char name[1];
} *deps;
@ -549,6 +551,57 @@ static void PM_InsertPackage(package_t *p)
numpackages++;
}
static qboolean PM_CheckFeature(const char *feature, const char **featurename, const char **concommand)
{
#ifdef HAVE_CLIENT
extern cvar_t r_replacemodels;
#endif
*featurename = NULL;
*concommand = NULL;
#ifdef HAVE_CLIENT
//check for compressed texture formats, to warn when not supported.
if (!strcmp(feature, "bc1") || !strcmp(feature, "bc2") || !strcmp(feature, "bc3") || !strcmp(feature, "s3tc"))
return *featurename="S3 Texture Compression", sh_config.hw_bc>=1;
if (!strcmp(feature, "bc4") || !strcmp(feature, "bc5") || !strcmp(feature, "rgtc"))
return *featurename="Red/Green Texture Compression", sh_config.hw_bc>=2;
if (!strcmp(feature, "bc6") || !strcmp(feature, "bc7") || !strcmp(feature, "bptc"))
return *featurename="Block Partitioned Texture Compression", sh_config.hw_bc>=3;
if (!strcmp(feature, "etc1"))
return *featurename="Ericson Texture Compression, Original", sh_config.hw_etc>=1;
if (!strcmp(feature, "etc2") || !strcmp(feature, "eac"))
return *featurename="Ericson Texture Compression, Revision 2", sh_config.hw_etc>=2;
if (!strcmp(feature, "astcldr") || !strcmp(feature, "astc"))
return *featurename="Adaptive Scalable Texture Compression (LDR)", sh_config.hw_astc>=1;
if (!strcmp(feature, "astchdr"))
return *featurename="Adaptive Scalable Texture Compression (HDR)", sh_config.hw_astc>=2;
if (!strcmp(feature, "24bit"))
return *featurename="24bit Textures", *concommand="seta gl_load24bit 1\n", gl_load24bit.ival;
if (!strcmp(feature, "md3"))
return *featurename="Replacement Models", *concommand="seta r_replacemodels md3 md2\n", !!strstr(r_replacemodels.string, "md3");
if (!strcmp(feature, "rtlights"))
return *featurename="Realtime Dynamic Lights", *concommand="seta r_shadow_realtime_dlight 1\n", r_shadow_realtime_dlight.ival||r_shadow_realtime_world.ival;
if (!strcmp(feature, "rtworld"))
return *featurename="Realtime World Lights", *concommand="seta r_shadow_realtime_dlight 1\nseta r_shadow_realtime_world 1\n", r_shadow_realtime_world.ival;
#endif
return false;
}
static qboolean PM_CheckPackageFeatures(package_t *p)
{
struct packagedep_s *dep;
const char *featname, *enablecmd;
for (dep = p->deps; dep; dep = dep->next)
{
if (dep->dtype == DEP_NEEDFEATURE)
{
if (!PM_CheckFeature(dep->name, &featname, &enablecmd))
return false;
}
}
return true;
}
static qboolean PM_CheckFile(const char *filename, enum fs_relative base)
{
@ -916,6 +969,8 @@ static qboolean PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *ur
PM_AddDep(p, DEP_RECOMMEND, val);
else if (!strcmp(key, "suggest"))
PM_AddDep(p, DEP_SUGGEST, val);
else if (!strcmp(key, "need"))
PM_AddDep(p, DEP_NEEDFEATURE, val);
else if (!strcmp(key, "test"))
flags |= DPF_TESTING;
else if (!strcmp(key, "stale") && version==2)
@ -1486,7 +1541,12 @@ static void PM_MarkPackage(package_t *package, unsigned int markflag)
{
d = PM_FindPackage(dep->name);
if (d)
PM_MarkPackage(d, DPF_AUTOMARKED);
{
if (dep->dtype == DEP_RECOMMEND && !PM_CheckPackageFeatures(d))
Con_DPrintf("Skipping recommendation \"%s\"\n", dep->name);
else
PM_MarkPackage(d, DPF_AUTOMARKED);
}
else
Con_DPrintf("Couldn't find dependancy \"%s\"\n", dep->name);
}
@ -1995,6 +2055,11 @@ static void PM_WriteInstalledPackages(void)
Q_strncatz(buf, " ", sizeof(buf));
COM_QuotedConcat(va("recommend=%s", dep->name), buf, sizeof(buf));
}
else if (dep->dtype == DEP_NEEDFEATURE)
{
Q_strncatz(buf, " ", sizeof(buf));
COM_QuotedConcat(va("need=%s", dep->name), buf, sizeof(buf));
}
}
if (p->flags & DPF_TESTING)
@ -2025,6 +2090,31 @@ static void PM_WriteInstalledPackages(void)
}
}
//package has been downloaded and installed, but some packages need to be enabled
//(plugins might have other dll dependancies, so this can only happen AFTER the entire package was extracted)
static void PM_PackageEnabled(package_t *p)
{
char ext[8];
struct packagedep_s *dep;
FS_FlushFSHashFull();
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_ReloadPackFiles();
#ifdef PLUGINS
if ((p->flags & DPF_PLUGIN) && !Q_strncasecmp(dep->name, PLUGINPREFIX, strlen(PLUGINPREFIX)))
Cmd_ExecuteString(va("plug_load %s\n", dep->name), RESTRICT_LOCAL);
#endif
#ifdef MENU_DAT
if (!Q_strcasecmp(dep->name, "menu.dat"))
Cmd_ExecuteString("menu_restart\n", RESTRICT_LOCAL);
#endif
}
}
#ifdef WEBCLIENT
//callback from PM_Download_Got, extracts each file from an archive
static int QDECL PM_ExtractFiles(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath)
@ -2057,31 +2147,6 @@ static int QDECL PM_ExtractFiles(const char *fname, qofs_t fsize, time_t mtime,
return 1;
}
//package has been downloaded and installed, but some packages need to be enabled
//(plugins might have other dll dependancies, so this can only happen AFTER the entire package was extracted)
static void PM_PackageEnabled(package_t *p)
{
char ext[8];
struct packagedep_s *dep;
FS_FlushFSHashFull();
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_ReloadPackFiles();
#ifdef PLUGINS
if ((p->flags & DPF_PLUGIN) && !Q_strncasecmp(dep->name, PLUGINPREFIX, strlen(PLUGINPREFIX)))
Cmd_ExecuteString(va("plug_load %s\n", dep->name), RESTRICT_LOCAL);
#endif
#ifdef MENU_DAT
if (!Q_strcasecmp(dep->name, "menu.dat"))
Cmd_ExecuteString("menu_restart\n", RESTRICT_LOCAL);
#endif
}
}
static void PM_StartADownload(void);
//callback from PM_StartADownload
static void PM_Download_Got(struct dl_download *dl)
@ -2334,10 +2399,10 @@ int PM_IsApplying(qboolean listsonly)
return count;
}
#ifdef WEBCLIENT
//looks for the next package that needs downloading, and grabs it
static void PM_StartADownload(void)
{
#ifdef WEBCLIENT
vfsfile_t *tmpfile;
char *temp;
package_t *p;
@ -2466,8 +2531,8 @@ static void PM_StartADownload(void)
//clear the updating flag once there's no more activity needed
pkg_updating = downloading;
#endif
}
#endif
//'just' starts doing all the things needed to remove/install selected packages
void PM_ApplyChanges(void)
{
@ -2611,8 +2676,45 @@ void PM_ApplyChanges(void)
if ((p->flags&DPF_MARKED) && !(p->flags&DPF_ENABLED) && !p->download)
p->trymirrors = ~0u;
}
#endif
PM_StartADownload(); //and try to do those downloads.
#else
for (p = availablepackages; p; p=p->next)
{
if ((p->flags&DPF_MARKED) && !(p->flags&DPF_ENABLED))
{ //flagged for a (re?)download
int i;
struct packagedep_s *dep;
for (i = 0; i < countof(p->mirror); i++)
if (p->mirror[i])
break;
for (dep = p->deps; dep; dep=dep->next)
if (dep->dtype == DEP_FILE)
break;
if (!dep && i == countof(p->mirror))
{ //this appears to be a meta package with no download
//just directly install it.
p->flags &= ~(DPF_NATIVE|DPF_CACHED|DPF_CORRUPT);
p->flags |= DPF_ENABLED;
Con_Printf("Enabled meta package %s\n", p->name);
PM_WriteInstalledPackages();
PM_PackageEnabled(p);
}
if ((p->flags & DPF_PRESENT) && !PM_PurgeOnDisable(p))
{ //its in our cache directory, so lets just use that
p->flags |= DPF_ENABLED;
Con_Printf("Enabled cached package %s\n", p->name);
PM_WriteInstalledPackages();
PM_PackageEnabled(p);
continue;
}
else
p->flags &= ~DPF_MARKED;
}
}
#endif
}
#if defined(M_Menu_Prompt) || defined(SERVERONLY)
@ -3202,8 +3304,12 @@ static void MD_Draw (int x, int y, struct menucustom_s *c, struct emenu_s *m)
if (p->flags & DPF_TESTING) //hide testing updates
n = va("^h%s", n);
// if (!(p->flags & (DPF_ENABLED|DPF_MARKED|DPF_PRESENT))
// continue;
if (!PM_CheckPackageFeatures(p))
Draw_FunStringWidth(0, y, "!", x+8, true, true);
// if (!(p->flags & (DPF_ENABLED|DPF_MARKED|DPF_PRESENT))
// continue;
// if (&m->selecteditem->common == &c->common)
// Draw_AltFunString (x+48, y, n);
@ -3404,6 +3510,7 @@ static int MD_AddItemsToDownloadMenu(emenu_t *m, int y, const char *pathprefix)
char *slash;
menuoption_t *mo;
int prefixlen = strlen(pathprefix);
struct packagedep_s *dep;
//add all packages in this dir
for (p = availablepackages; p; p = p->next)
@ -3420,10 +3527,26 @@ static int MD_AddItemsToDownloadMenu(emenu_t *m, int y, const char *pathprefix)
desc = va("^aauthor: ^a%s\n^alicense: ^a%s\n^awebsite: ^a%s\n%s", p->author?p->author:"^hUnknown^h", p->license?p->license:"^hUnknown^h", p->website?p->website:"^hUnknown^h", p->description);
else
desc = p->description;
for (dep = p->deps; dep; dep = dep->next)
{
if (dep->dtype == DEP_NEEDFEATURE)
{
const char *featname, *enablecmd;
if (!PM_CheckFeature(dep->name, &featname, &enablecmd))
{
if (enablecmd)
desc = va("^aDisabled: ^a%s\n%s", featname, desc);
else
desc = va("^aUnavailable: ^a%s\n%s", featname, desc);
}
}
}
c = MC_AddCustom(m, 0, y, p, downloadablessequence, desc);
c->draw = MD_Draw;
c->key = MD_Key;
c->common.width = 320;
c->common.width = 320-16;
c->common.height = 8;
y += 8;

View File

@ -479,7 +479,7 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, emenu_t *men
if (option->common.ishidden)
continue;
if (&menu->menu == topmenu && menu->mouseitem == option)
if (&menu->menu == topmenu && menu->mouseitem == option && option->common.type != mt_frameend)
{
float alphamax = 0.5, alphamin = 0.2;
R2D_ImageColours(.5,.4,0,(sin(realtime*2)+1)*0.5*(alphamax-alphamin)+alphamin);

View File

@ -241,7 +241,7 @@ typedef struct image_s
int status; //TEX_
unsigned int flags;
struct image_s *next;
struct image_s *prev;
// struct image_s *prev;
struct image_s *aliasof;
union
{
@ -371,16 +371,16 @@ typedef struct
typedef struct texnums_s {
char mapname[MAX_QPATH]; //the 'official' name of the diffusemap. used to generate filenames for other textures.
texid_t base; //regular diffuse texture. may have alpha if surface is transparent
texid_t base; //regular diffuse texture. may have alpha if surface is transparent.
texid_t bump; //normalmap. height values packed in alpha.
texid_t specular; //specular lighting values.
texid_t upperoverlay; //diffuse texture for the upper body(shirt colour). no alpha channel. added to base.rgb
texid_t loweroverlay; //diffuse texture for the lower body(trouser colour). no alpha channel. added to base.rgb
texid_t specular; //specular lighting values. alpha contains exponent multiplier
texid_t upperoverlay; //diffuse texture for the upper body(shirt colour). no alpha channel. added to base.rgb. ideally an l8 texture
texid_t loweroverlay; //diffuse texture for the lower body(trouser colour). no alpha channel. added to base.rgb. ideally an l8 texture
texid_t paletted; //8bit paletted data, just because.
texid_t fullbright;
texid_t reflectcube;
texid_t reflectmask;
texid_t displacement;
texid_t fullbright; //emissive texture. alpha should be 1.
texid_t reflectcube; //for fake reflections
texid_t reflectmask; //defines how reflective it is (for cubemap reflections)
texid_t displacement; //alternative to bump.a, eg R16[F] for offsetmapping or tessellation
texid_t occlusion; //occlusion map...
//the material's pushconstants. vulkan guarentees only 128 bytes. so 8 vec4s. note that lmscales should want 4 of them...

View File

@ -727,7 +727,8 @@ static void QCBUILTIN PF_cs_remove (pubprogfuncs_t *prinst, struct globalvars_s
return;
}
pe->DelinkTrailstate(&ed->trailstate);
if (pe)
pe->DelinkTrailstate(&ed->trailstate);
World_UnlinkEdict((wedict_t*)ed);
ED_Free (prinst, (void*)ed);
}
@ -7362,7 +7363,7 @@ void ASMCALL CSQC_ThinkTimeOp(pubprogfuncs_t *progs, edict_t *ed, float var)
vars->nextthink = *w->g.time+var;
}
pbool PDECL CSQC_CheckHeaderCrc(pubprogfuncs_t *progs, progsnum_t num, int crc)
pbool PDECL CSQC_CheckHeaderCrc(pubprogfuncs_t *progs, progsnum_t num, int crc, const char *filename)
{
if (!num)
{

View File

@ -2686,11 +2686,11 @@ void MP_CvarChanged(cvar_t *var)
}
}
pbool PDECL Menu_CheckHeaderCrc(pubprogfuncs_t *inst, progsnum_t idx, int crc)
pbool PDECL Menu_CheckHeaderCrc(pubprogfuncs_t *inst, progsnum_t idx, int crc, const char *filename)
{
if (crc == 10020)
return true; //its okay
Con_Printf("progs crc is invalid for menuqc\n");
Con_Printf("progs crc is invalid for %s\n", filename);
return false;
}

View File

@ -3686,7 +3686,7 @@ uploadfmt_t Surf_LightmapMode(model_t *model)
fmt = PTI_RGBA32F;
else if (sh_config.texfmt[PTI_A2BGR10] && rgb)
fmt = PTI_A2BGR10;
else if (sh_config.texfmt[PTI_L8] && !rgb && !r_deluxemapping)
else if (sh_config.texfmt[PTI_L8] && !rgb && !r_deluxemapping && r_dynamic.ival<=0)
fmt = PTI_L8;
else if (sh_config.texfmt[PTI_BGRX8])
fmt = PTI_BGRX8;

View File

@ -423,6 +423,7 @@ enum imageflags
IF_NOGAMMA = 1<<9, /*do not apply texture-based gamma*/
IF_3DMAP = 1<<10, /*waning - don't test directly*/
IF_CUBEMAP = 1<<11, /*waning - don't test directly*/
IF_2DARRAY = IF_3DMAP|IF_CUBEMAP,
IF_TEXTYPE = (1<<10) | (1<<11), /*0=2d, 1=3d, 2=cubeface, 3=2d array texture*/
IF_TEXTYPESHIFT = 10, /*0=2d, 1=3d, 2-7=cubeface*/
IF_MIPCAP = 1<<12, //allow the use of d_mipcap
@ -593,7 +594,7 @@ void RQ_Shutdown(void);
void WritePCXfile (const char *filename, enum fs_relative fsroot, qbyte *data, int width, int height, int rowbytes, qbyte *palette, qboolean upload); //data is 8bit.
qbyte *ReadPCXFile(qbyte *buf, int length, int *width, int *height);
qbyte *ReadTargaFile(qbyte *buf, int length, int *width, int *height, uploadfmt_t *format, qboolean greyonly, uploadfmt_t forceformat);
void *ReadTargaFile(qbyte *buf, int length, int *width, int *height, uploadfmt_t *format, qboolean greyonly, uploadfmt_t forceformat);
qbyte *ReadJPEGFile(qbyte *infile, int length, int *width, int *height);
qbyte *ReadPNGFile(const char *fname, qbyte *buf, int length, int *width, int *height, uploadfmt_t *format);
qbyte *ReadPCXPalette(qbyte *buf, int len, qbyte *out);

View File

@ -36,7 +36,6 @@ qboolean vid_isfullscreen;
#define GLRENDEREROPTIONS "GL Renderer Options" //fixme: often used for generic cvars that apply to more than just gl...
#define D3DRENDEREROPTIONS "D3D Renderer Options"
#define VKRENDEREROPTIONS "Vulkan-Specific Renderer Options"
unsigned int d_8to24rgbtable[256];
unsigned int d_8to24srgbtable[256];
@ -239,7 +238,7 @@ cvar_t scr_allowsnap = CVARF ("scr_allowsnap", "1",
CVAR_NOTFROMSERVER);
cvar_t scr_centersbar = CVAR ("scr_centersbar", "2");
cvar_t scr_centertime = CVAR ("scr_centertime", "2");
cvar_t scr_logcenterprint = CVARD ("con_logcenterprint", "1", "Specifies whether to print centerprints on the console.\n0: never\n1: single-player or coop only.\n2: always.\n");
cvar_t scr_logcenterprint = CVARD ("con_logcenterprint", "1", "Specifies whether to print centerprints on the console.\n0: never\n1: single-player or coop only.\n2: always.");
cvar_t scr_conalpha = CVARC ("scr_conalpha", "0.7",
Cvar_Limiter_ZeroToOne_Callback);
cvar_t scr_consize = CVAR ("scr_consize", "0.5");
@ -455,7 +454,7 @@ cvar_t r_glsl_offsetmapping_reliefmapping = CVARFD("r_glsl_offsetmapping_reliefm
cvar_t r_glsl_turbscale_reflect = CVARFD ("r_glsl_turbscale_reflect", "1", CVAR_ARCHIVE, "Controls the strength of the water reflection ripples (used by the altwater glsl code).");
cvar_t r_glsl_turbscale_refract = CVARFD ("r_glsl_turbscale_refract", "1", CVAR_ARCHIVE, "Controls the strength of the underwater ripples (used by the altwater glsl code).");
cvar_t r_fastturbcolour = CVARFD ("r_fastturbcolour", "0.1 0.2 0.3", CVAR_ARCHIVE, "The colour to use for water surfaces draw with r_waterstyle 0.\n");
cvar_t r_fastturbcolour = CVARFD ("r_fastturbcolour", "0.1 0.2 0.3", CVAR_ARCHIVE, "The colour to use for water surfaces draw with r_waterstyle 0.");
cvar_t r_waterstyle = CVARFD ("r_waterstyle", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Changes how water, and teleporters are drawn. Possible values are:\n0: fastturb-style block colour.\n1: regular q1-style water.\n2: refraction(ripply and transparent)\n3: refraction with reflection at an angle\n4: ripplemapped without reflections (requires particle effects)\n5: ripples+reflections");
cvar_t r_slimestyle = CVARFD ("r_slimestyle", "", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "See r_waterstyle, but affects only slime. If empty, defers to r_waterstyle.");
cvar_t r_lavastyle = CVARFD ("r_lavastyle", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "See r_waterstyle, but affects only lava. If empty, defers to r_waterstyle.");
@ -477,21 +476,6 @@ extern cvar_t gl_dither;
cvar_t gl_screenangle = CVAR("gl_screenangle", "0");
#endif
#ifdef VKQUAKE
cvar_t vk_stagingbuffers = CVARFD ("vk_stagingbuffers", "", CVAR_RENDERERLATCH, "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(niform), e(lements), v(ertex), 0(none).");
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 = CVARFD("vk_debug", "0", CVAR_VIDEOLATCH, "Register a debug handler to display driver/layer messages. 2 enables the standard validation layers.");
cvar_t vk_dualqueue = CVARFD("vk_dualqueue", "", CVAR_VIDEOLATCH, "Attempt to use a separate queue for presentation. Blank for default.");
cvar_t vk_busywait = CVARD ("vk_busywait", "", "Force busy waiting until the GPU finishes doing its thing.");
cvar_t vk_waitfence = CVARD ("vk_waitfence", "", "Waits on fences, instead of semaphores. This is more likely to result in gpu stalls while the cpu waits.");
cvar_t vk_usememorypools = CVARFD("vk_usememorypools", "", CVAR_VIDEOLATCH, "Allocates memory pools for sub allocations. Vulkan has a limit to the number of memory allocations allowed so this should always be enabled, however at this time FTE is unable to reclaim pool memory, and would require periodic vid_restarts to flush them.");
cvar_t vk_nv_glsl_shader = CVARFD("vk_loadglsl", "", CVAR_VIDEOLATCH, "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 glsl compile errors). Don't forget to do a vid_restart after.");
cvar_t vk_khr_get_memory_requirements2 = CVARFD("vk_khr_get_memory_requirements2", "", CVAR_VIDEOLATCH, "Enable extended memory info querires");
cvar_t vk_khr_dedicated_allocation = CVARFD("vk_khr_dedicated_allocation", "", CVAR_VIDEOLATCH, "Flag vulkan memory allocations as dedicated, where applicable.");
cvar_t vk_khr_push_descriptor = CVARFD("vk_khr_push_descriptor", "", CVAR_VIDEOLATCH, "Enables better descriptor streaming.");
cvar_t vk_amd_rasterization_order = CVARFD("vk_amd_rasterization_order", "", CVAR_VIDEOLATCH, "Enables the use of relaxed rasterization ordering, for a small speedup at the minor risk of a little zfighting.");
#endif
#ifdef D3D9QUAKE
cvar_t d3d9_hlsl = CVAR("d3d_hlsl", "1");
#endif
@ -506,6 +490,8 @@ void GLD3DRenderer_Init(void)
#endif
#if defined(GLQUAKE)
extern cvar_t gl_blacklist_texture_compression;
extern cvar_t gl_blacklist_generatemipmap;
void GLRenderer_Init(void)
{
//gl-specific video vars
@ -567,6 +553,8 @@ void GLRenderer_Init(void)
Cvar_Register (&r_shaderblobs, GLRENDEREROPTIONS);
Cvar_Register (&gl_compress, GLRENDEREROPTIONS);
Cvar_Register (&gl_blacklist_texture_compression, "gl blacklists");
Cvar_Register (&gl_blacklist_generatemipmap, "gl blacklists");
// Cvar_Register (&gl_detail, GRAPHICALNICETIES);
// Cvar_Register (&gl_detailscale, GRAPHICALNICETIES);
Cvar_Register (&gl_overbright, GRAPHICALNICETIES);
@ -1023,19 +1011,7 @@ void Renderer_Init(void)
Cvar_Register (&dpcompat_nopremulpics, GLRENDEREROPTIONS);
#endif
#ifdef VKQUAKE
Cvar_Register (&vk_stagingbuffers, VKRENDEREROPTIONS);
Cvar_Register (&vk_submissionthread, VKRENDEREROPTIONS);
Cvar_Register (&vk_debug, VKRENDEREROPTIONS);
Cvar_Register (&vk_dualqueue, VKRENDEREROPTIONS);
Cvar_Register (&vk_busywait, VKRENDEREROPTIONS);
Cvar_Register (&vk_waitfence, VKRENDEREROPTIONS);
Cvar_Register (&vk_usememorypools, VKRENDEREROPTIONS);
Cvar_Register (&vk_nv_glsl_shader, VKRENDEREROPTIONS);
Cvar_Register (&vk_khr_get_memory_requirements2,VKRENDEREROPTIONS);
Cvar_Register (&vk_khr_dedicated_allocation,VKRENDEREROPTIONS);
Cvar_Register (&vk_khr_push_descriptor, VKRENDEREROPTIONS);
Cvar_Register (&vk_amd_rasterization_order, VKRENDEREROPTIONS);
VK_RegisterVulkanCvars();
#endif
// misc
@ -1870,6 +1846,7 @@ void R_ReloadRenderer_f (void)
BZ_Free(portalblob);
}
#endif
Con_DPrintf("vid_reload time: %f\n", Sys_DoubleTime() - time);
}
static int R_PriorityForRenderer(rendererinfo_t *r)

View File

@ -115,7 +115,7 @@ typedef enum uploadfmt
//floating point formats
PTI_R16F,
PTI_R32F,
PTI_RGBA16F, //consider using e5bgr9
PTI_RGBA16F, //consider using e5bgr9 or bc6/astc
PTI_RGBA32F, //usually overkill
//packed/misaligned formats: these are specified in native endian order (high bits listed first because that's how things are represented in hex), so may need byte swapping...
PTI_A2BGR10, //mostly for rendertargets, might also be useful for overbight lightmaps.
@ -126,63 +126,79 @@ typedef enum uploadfmt
PTI_RGBA5551, //16bit alpha format (gl).
PTI_ARGB1555, //16bit alpha format (d3d).
//(desktop/tegra) compressed formats
PTI_BC1_RGB,
PTI_BC1_RGB_SRGB,
PTI_BC1_RGBA,
PTI_BC1_RGBA_SRGB,
PTI_BC2_RGBA,
PTI_BC2_RGBA_SRGB,
PTI_BC3_RGBA, //maybe add a bc3 normalmapswizzle type for d3d9?
PTI_BC3_RGBA_SRGB,
PTI_BC4_R8, //greyscale, kinda
PTI_BC4_R8_SNORM,
PTI_BC5_RG8, //useful for normalmaps
PTI_BC5_RG8_SNORM, //useful for normalmaps
PTI_BC6_RGB_UFLOAT, //unsigned (half) floats!
PTI_BC6_RGB_SFLOAT, //signed (half) floats!
PTI_BC7_RGBA, //multimode compression, using as many bits as bc2/bc3
PTI_BC7_RGBA_SRGB,
PTI_BC1_RGB, /*4bpp*/
PTI_BC1_RGB_SRGB, /*4bpp*/
PTI_BC1_RGBA, /*4bpp*/
PTI_BC1_RGBA_SRGB, /*4bpp*/
PTI_BC2_RGBA, /*8bpp*/
PTI_BC2_RGBA_SRGB, /*8bpp*/
PTI_BC3_RGBA, /*8bpp*/ //maybe add a bc3 normalmapswizzle type for d3d9?
PTI_BC3_RGBA_SRGB, /*8bpp*/
PTI_BC4_R8, /*4bpp*/ //greyscale, kinda
PTI_BC4_R8_SNORM, /*4bpp*/
PTI_BC5_RG8, /*8bpp*/ //useful for normalmaps
PTI_BC5_RG8_SNORM, /*8bpp*/ //useful for normalmaps
PTI_BC6_RGB_UFLOAT, /*8bpp*/ //unsigned (half) floats!
PTI_BC6_RGB_SFLOAT, /*8bpp*/ //signed (half) floats!
PTI_BC7_RGBA, /*8bpp*/ //multimode compression, using as many bits as bc2/bc3
PTI_BC7_RGBA_SRGB, /*8bpp*/
//(mobile/intel) compressed formats
PTI_ETC1_RGB8, //limited form
PTI_ETC2_RGB8, //extended form
PTI_ETC2_RGB8A1,
PTI_ETC2_RGB8A8,
PTI_ETC2_RGB8_SRGB,
PTI_ETC2_RGB8A1_SRGB,
PTI_ETC2_RGB8A8_SRGB,
PTI_EAC_R11, //might be useful for overlays, with swizzles.
PTI_EAC_R11_SNORM, //no idea what this might be used for, whatever
PTI_EAC_RG11, //useful for normalmaps (calculate blue)
PTI_EAC_RG11_SNORM, //useful for normalmaps (calculate blue)
//astc... zomg
PTI_ASTC_4X4,
PTI_ETC1_RGB8, /*4bpp*/ //limited form
PTI_ETC2_RGB8, /*4bpp*/ //extended form
PTI_ETC2_RGB8A1, /*4bpp*/
PTI_ETC2_RGB8A8, /*8bpp*/
PTI_ETC2_RGB8_SRGB, /*4bpp*/
PTI_ETC2_RGB8A1_SRGB,/*4bpp*/
PTI_ETC2_RGB8A8_SRGB,/*8bpp*/
PTI_EAC_R11, /*4bpp*/ //might be useful for overlays, with swizzles.
PTI_EAC_R11_SNORM, /*4bpp*/ //no idea what this might be used for, whatever
PTI_EAC_RG11, /*8bpp*/ //useful for normalmaps (calculate blue)
PTI_EAC_RG11_SNORM, /*8bpp*/ //useful for normalmaps (calculate blue)
//astc... zomg.
PTI_ASTC_4X4_LDR, /*8bpp*/ //ldr/srgb/hdr formats are technically all the same.
PTI_ASTC_5X4_LDR, /*6.40*/ //srgb formats are different because of an extra srgb lookup step
PTI_ASTC_5X5_LDR, /*5.12*/ //ldr formats are identical to hdr except for the extended colour modes disabled.
PTI_ASTC_6X5_LDR, /*4.17*/
PTI_ASTC_6X6_LDR, /*3.56*/
PTI_ASTC_8X5_LDR, /*3.20*/
PTI_ASTC_8X6_LDR, /*2.67*/
PTI_ASTC_10X5_LDR, /*2.56*/
PTI_ASTC_10X6_LDR, /*2.13*/
PTI_ASTC_8X8_LDR, /*2bpp*/
PTI_ASTC_10X8_LDR, /*1.60*/
PTI_ASTC_10X10_LDR, /*1.28*/
PTI_ASTC_12X10_LDR, /*1.07*/
PTI_ASTC_12X12_LDR, /*0.89*/
PTI_ASTC_4X4_SRGB,
PTI_ASTC_5X4,
PTI_ASTC_5X4_SRGB,
PTI_ASTC_5X5,
PTI_ASTC_5X5_SRGB,
PTI_ASTC_6X5,
PTI_ASTC_6X5_SRGB,
PTI_ASTC_6X6,
PTI_ASTC_6X6_SRGB,
PTI_ASTC_8X5,
PTI_ASTC_8X5_SRGB,
PTI_ASTC_8X6,
PTI_ASTC_8X6_SRGB,
PTI_ASTC_10X5,
PTI_ASTC_10X5_SRGB,
PTI_ASTC_10X6,
PTI_ASTC_10X6_SRGB,
PTI_ASTC_8X8,
PTI_ASTC_8X8_SRGB,
PTI_ASTC_10X8,
PTI_ASTC_10X8_SRGB,
PTI_ASTC_10X10,
PTI_ASTC_10X10_SRGB,
PTI_ASTC_12X10,
PTI_ASTC_12X10_SRGB,
PTI_ASTC_12X12,
PTI_ASTC_12X12_SRGB,
PTI_ASTC_4X4_HDR, //these are not strictly necessary, and are likely to be treated identically to the ldr versions, but they may use extra features that the hardware does not support
PTI_ASTC_5X4_HDR,
PTI_ASTC_5X5_HDR,
PTI_ASTC_6X5_HDR,
PTI_ASTC_6X6_HDR,
PTI_ASTC_8X5_HDR,
PTI_ASTC_8X6_HDR,
PTI_ASTC_10X5_HDR,
PTI_ASTC_10X6_HDR,
PTI_ASTC_8X8_HDR,
PTI_ASTC_10X8_HDR,
PTI_ASTC_10X10_HDR,
PTI_ASTC_12X10_HDR,
PTI_ASTC_12X12_HDR,
#define PTI_ASTC_FIRST PTI_ASTC_4X4_LDR
#define PTI_ASTC_LAST PTI_ASTC_12X12_HDR
//depth formats
PTI_DEPTH16,
@ -200,12 +216,12 @@ typedef enum uploadfmt
TF_TRANS8, /*8bit quake-palette image, index 255=transparent*/
TF_TRANS8_FULLBRIGHT, /*fullbright 8 - fullbright texels have alpha 255, everything else 0*/
TF_HEIGHT8, /*image data is greyscale, convert to a normalmap and load that, uploaded alpha contains the original heights*/
TF_HEIGHT8PAL, /*source data is palette values rather than actual heights, generate a fallback heightmap*/
TF_HEIGHT8PAL, /*source data is palette values rather than actual heights, generate a fallback heightmap. actual palette is ignored...*/
TF_H2_T7G1, /*8bit data, odd indexes give greyscale transparence*/
TF_H2_TRANS8_0, /*8bit data, 0 is transparent, not 255*/
TF_H2_T4A4, /*8bit data, weird packing*/
PTI_LLLX8, /*RGB data where the RGB values were all the same. we can convert to L8 to use less memory (common with shirt/pants/reflection)*/
PTI_LLLX8, /*RGBX data where the RGB values were all the same. we can convert to L8 to use less memory (common with shirt/pants/reflection)*/
PTI_LLLA8, /*RGBA data where the RGB values were all the same. we can convert to LA8 to use less memory (common with gloss)*/
/*this block requires an explicit (separate) palette*/

View File

@ -202,6 +202,46 @@ static qboolean Alsa_InitAlsa(void)
{
static qboolean tried;
static qboolean alsaworks;
static dllfunction_t funcs[] =
{
{(void**)&psnd_pcm_open, "snd_pcm_open"},
{(void**)&psnd_pcm_close, "snd_pcm_close"},
{(void**)&psnd_config_update_free_global, "snd_config_update_free_global"},
{(void**)&psnd_strerror, "snd_strerror"},
{(void**)&psnd_pcm_hw_params_any, "snd_pcm_hw_params_any"},
{(void**)&psnd_pcm_hw_params_set_access, "snd_pcm_hw_params_set_access"},
{(void**)&psnd_pcm_hw_params_set_format, "snd_pcm_hw_params_set_format"},
{(void**)&psnd_pcm_hw_params_set_channels, "snd_pcm_hw_params_set_channels"},
{(void**)&psnd_pcm_hw_params_set_rate_near, "snd_pcm_hw_params_set_rate_near"},
{(void**)&psnd_pcm_hw_params_set_period_size_near, "snd_pcm_hw_params_set_period_size_near"},
{(void**)&psnd_pcm_hw_params, "snd_pcm_hw_params"},
{(void**)&psnd_pcm_sw_params_current, "snd_pcm_sw_params_current"},
{(void**)&psnd_pcm_sw_params_set_start_threshold, "snd_pcm_sw_params_set_start_threshold"},
{(void**)&psnd_pcm_sw_params_set_stop_threshold, "snd_pcm_sw_params_set_stop_threshold"},
{(void**)&psnd_pcm_sw_params, "snd_pcm_sw_params"},
{(void**)&psnd_pcm_hw_params_get_buffer_size, "snd_pcm_hw_params_get_buffer_size"},
{(void**)&psnd_pcm_avail_update, "snd_pcm_avail_update"},
{(void**)&psnd_pcm_state, "snd_pcm_state"},
{(void**)&psnd_pcm_start, "snd_pcm_start"},
{(void**)&psnd_pcm_recover, "snd_pcm_recover"},
{(void**)&psnd_pcm_set_params, "snd_pcm_set_params"},
{(void**)&psnd_pcm_hw_params_sizeof, "snd_pcm_hw_params_sizeof"},
{(void**)&psnd_pcm_sw_params_sizeof, "snd_pcm_sw_params_sizeof"},
{(void**)&psnd_pcm_hw_params_set_buffer_size_near, "snd_pcm_hw_params_set_buffer_size_near"},
{(void**)&psnd_pcm_mmap_begin, "snd_pcm_mmap_begin"},
{(void**)&psnd_pcm_mmap_commit, "snd_pcm_mmap_commit"},
{(void**)&psnd_pcm_writei, "snd_pcm_writei"},
{(void**)&psnd_pcm_prepare, "snd_pcm_prepare"},
{(void**)&psnd_device_name_hint, "snd_device_name_hint"},
{(void**)&psnd_device_name_get_hint, "snd_device_name_get_hint"},
{(void**)&psnd_device_name_free_hint, "snd_device_name_free_hint"},
{NULL,NULL}
};
if (tried)
return alsaworks;
tried = true;
@ -211,80 +251,13 @@ static qboolean Alsa_InitAlsa(void)
return false;
// Try alternative names of libasound, sometimes it is not linked correctly.
alsasharedobject = dlopen("libasound.so.2", RTLD_LAZY|RTLD_LOCAL);
alsasharedobject = Sys_LoadLibrary("libasound.so.2", funcs);
if (!alsasharedobject)
{
alsasharedobject = dlopen("libasound.so", RTLD_LAZY|RTLD_LOCAL);
if (!alsasharedobject)
{
return false;
}
}
psnd_pcm_open = dlsym(alsasharedobject, "snd_pcm_open");
psnd_pcm_close = dlsym(alsasharedobject, "snd_pcm_close");
psnd_config_update_free_global = dlsym(alsasharedobject, "snd_config_update_free_global");
psnd_strerror = dlsym(alsasharedobject, "snd_strerror");
psnd_pcm_hw_params_any = dlsym(alsasharedobject, "snd_pcm_hw_params_any");
psnd_pcm_hw_params_set_access = dlsym(alsasharedobject, "snd_pcm_hw_params_set_access");
psnd_pcm_hw_params_set_format = dlsym(alsasharedobject, "snd_pcm_hw_params_set_format");
psnd_pcm_hw_params_set_channels = dlsym(alsasharedobject, "snd_pcm_hw_params_set_channels");
psnd_pcm_hw_params_set_rate_near = dlsym(alsasharedobject, "snd_pcm_hw_params_set_rate_near");
psnd_pcm_hw_params_set_period_size_near = dlsym(alsasharedobject, "snd_pcm_hw_params_set_period_size_near");
psnd_pcm_hw_params = dlsym(alsasharedobject, "snd_pcm_hw_params");
psnd_pcm_sw_params_current = dlsym(alsasharedobject, "snd_pcm_sw_params_current");
psnd_pcm_sw_params_set_start_threshold = dlsym(alsasharedobject, "snd_pcm_sw_params_set_start_threshold");
psnd_pcm_sw_params_set_stop_threshold = dlsym(alsasharedobject, "snd_pcm_sw_params_set_stop_threshold");
psnd_pcm_sw_params = dlsym(alsasharedobject, "snd_pcm_sw_params");
psnd_pcm_hw_params_get_buffer_size = dlsym(alsasharedobject, "snd_pcm_hw_params_get_buffer_size");
psnd_pcm_avail_update = dlsym(alsasharedobject, "snd_pcm_avail_update");
psnd_pcm_state = dlsym(alsasharedobject, "snd_pcm_state");
psnd_pcm_start = dlsym(alsasharedobject, "snd_pcm_start");
psnd_pcm_recover = dlsym(alsasharedobject, "snd_pcm_recover");
psnd_pcm_set_params = dlsym(alsasharedobject, "snd_pcm_set_params");
psnd_pcm_hw_params_sizeof = dlsym(alsasharedobject, "snd_pcm_hw_params_sizeof");
psnd_pcm_sw_params_sizeof = dlsym(alsasharedobject, "snd_pcm_sw_params_sizeof");
psnd_pcm_hw_params_set_buffer_size_near = dlsym(alsasharedobject, "snd_pcm_hw_params_set_buffer_size_near");
psnd_pcm_mmap_begin = dlsym(alsasharedobject, "snd_pcm_mmap_begin");
psnd_pcm_mmap_commit = dlsym(alsasharedobject, "snd_pcm_mmap_commit");
psnd_pcm_writei = dlsym(alsasharedobject, "snd_pcm_writei");
psnd_pcm_prepare = dlsym(alsasharedobject, "snd_pcm_prepare");
psnd_device_name_hint = dlsym(alsasharedobject, "snd_device_name_hint");
psnd_device_name_get_hint = dlsym(alsasharedobject, "snd_device_name_get_hint");
psnd_device_name_free_hint = dlsym(alsasharedobject, "snd_device_name_free_hint");
alsaworks = psnd_pcm_open
&& psnd_pcm_close
&& psnd_config_update_free_global
&& psnd_strerror
&& psnd_pcm_hw_params_any
&& psnd_pcm_hw_params_set_access
&& psnd_pcm_hw_params_set_format
&& psnd_pcm_hw_params_set_channels
&& psnd_pcm_hw_params_set_rate_near
&& psnd_pcm_hw_params_set_period_size_near
&& psnd_pcm_hw_params
&& psnd_pcm_sw_params_current
&& psnd_pcm_sw_params_set_start_threshold
&& psnd_pcm_sw_params_set_stop_threshold
&& psnd_pcm_sw_params
&& psnd_pcm_hw_params_get_buffer_size
&& psnd_pcm_avail_update
&& psnd_pcm_state
&& psnd_pcm_start
&& psnd_pcm_hw_params_sizeof
&& psnd_pcm_sw_params_sizeof
&& psnd_pcm_hw_params_set_buffer_size_near
&& psnd_pcm_mmap_begin
&& psnd_pcm_mmap_commit
&& psnd_pcm_writei && psnd_pcm_prepare
&& psnd_device_name_hint && psnd_device_name_get_hint && psnd_device_name_free_hint
;
alsasharedobject = Sys_LoadLibrary("libasound.so", funcs);
if (!alsasharedobject)
return false;
alsaworks = true;
return alsaworks;
}

View File

@ -3143,12 +3143,13 @@ float S_GetChannelLevel(int entnum, int entchannel)
if (sc->channel[i].entnum == entnum && sc->channel[i].entchannel == entchannel && sc->channel[i].sfx)
{
ssamplepos_t spos = sc->GetChannelPos?sc->GetChannelPos(sc, &sc->channel[i]):(sc->channel[i].pos>>PITCHSHIFT);
if (sc->channel[i].sfx->decoder.decodedata)scache = sc->channel[i].sfx->decoder.decodedata(sc->channel[i].sfx, &scachebuf, spos, 1);
if (sc->channel[i].sfx->decoder.decodedata)
scache = sc->channel[i].sfx->decoder.decodedata(sc->channel[i].sfx, &scachebuf, spos, 1);
else
scache = NULL;
if (!scache)
scache = sc->channel[i].sfx->decoder.buf;
if (scache && spos >= scache->soundoffset && spos < scache->soundoffset+scache->length)
{
spos -= scache->soundoffset;

View File

@ -1,5 +1,5 @@
#include "quakedef.h"
#ifdef HAVE_MIXER
#if defined(HAVE_MIXER) && defined(MULTITHREAD)
#if 0
#include <pulse/simple.h>

View File

@ -128,13 +128,13 @@ static qboolean SSDL_InitAudio(void)
#endif
if (!inited)
if(SDL_InitSubSystem(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE))
{
{
if(0==SDL_InitSubSystem(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE))
inited = true;
else
Con_Printf("Couldn't initialize SDL audio subsystem (%s)\n", SDL_GetError());
return false;
}
inited = true;
return true;
}
return inited;
}
#else
#define SDL_VERSION_ATLEAST(x,y,z) 0

View File

@ -99,7 +99,7 @@ qboolean isDedicated;
#if 1
static int ansiremap[8] = {0, 4, 2, 6, 1, 5, 3, 7};
static void ApplyColour(unsigned int chrflags)
static void ApplyColour(FILE *out, unsigned int chrflags)
{
static int oldflags = CON_WHITEMASK;
int bg, fg;
@ -108,10 +108,10 @@ static void ApplyColour(unsigned int chrflags)
return;
oldflags = chrflags;
printf("\e[0;"); // reset
fprintf(out, "\e[0;"); // reset
if (chrflags & CON_BLINKTEXT)
printf("5;"); // set blink
fprintf(out, "5;"); // set blink
bg = (chrflags & CON_BGMASK) >> CON_BGSHIFT;
fg = (chrflags & CON_FGMASK) >> CON_FGSHIFT;
@ -124,12 +124,12 @@ static void ApplyColour(unsigned int chrflags)
{
if (fg & 0x8) // intensive bit set for foreground
{
printf("1;"); // set bold/intensity ansi flag
fprintf(out, "1;"); // set bold/intensity ansi flag
fg &= 0x7; // strip intensive bit
}
// set foreground and background colors
printf("3%i;4%im", ansiremap[fg], ansiremap[bg]);
fprintf(out, "3%i;4%im", ansiremap[fg], ansiremap[bg]);
}
else
{
@ -137,22 +137,22 @@ static void ApplyColour(unsigned int chrflags)
{
//to get around wierd defaults (like a white background) we have these special hacks for colours 0 and 7
case COLOR_BLACK:
printf("7m"); // set inverse
fprintf(out, "7m"); // set inverse
break;
case COLOR_GREY:
printf("1;30m"); // treat as dark grey
fprintf(out, "1;30m"); // treat as dark grey
break;
case COLOR_WHITE:
printf("m"); // set nothing else
fprintf(out, "m"); // set nothing else
break;
default:
if (fg & 0x8) // intensive bit set for foreground
{
printf("1;"); // set bold/intensity ansi flag
fprintf(out, "1;"); // set bold/intensity ansi flag
fg &= 0x7; // strip intensive bit
}
printf("3%im", ansiremap[fg]); // set foreground
fprintf(out, "3%im", ansiremap[fg]); // set foreground
break;
}
}
@ -167,9 +167,16 @@ void Sys_Printf (char *fmt, ...)
conchar_t *c, *e;
wchar_t w;
unsigned int codeflags, codepoint;
FILE *out = stdout;
if (nostdout)
{
#ifdef _DEBUG
out = stderr;
#else
return;
#endif
}
va_start (argptr,fmt);
vsnprintf (text,sizeof(text)-1, fmt,argptr);
@ -188,26 +195,26 @@ void Sys_Printf (char *fmt, ...)
if ((codeflags&CON_RICHFORECOLOUR) || (codepoint == '\n' && (codeflags&CON_NONCLEARBG)))
codeflags = CON_WHITEMASK; //make sure we don't get annoying backgrounds on other lines.
ApplyColour(codeflags);
ApplyColour(out, codeflags);
w = codepoint;
if (w >= 0xe000 && w < 0xe100)
{
/*not all quake chars are ascii compatible, so map those control chars to safe ones so we don't mess up anyone's xterm*/
if ((w & 0x7f) > 0x20)
putc(w&0x7f, stdout);
putc(w&0x7f, out);
else if (w & 0x80)
{
static char tab[32] = "---#@.@@@@ # >.." "[]0123456789.---";
putc(tab[w&31], stdout);
putc(tab[w&31], out);
}
else
{
static char tab[32] = ".####.#### # >.." "[]0123456789.---";
putc(tab[w&31], stdout);
putc(tab[w&31], out);
}
}
else if (w < ' ' && w != '\t' && w != '\r' && w != '\n')
putc('?', stdout); //don't let anyone print escape codes or other things that could crash an xterm.
putc('?', out); //don't let anyone print escape codes or other things that could crash an xterm.
else
{
/*putwc doesn't like me. force it in utf8*/
@ -215,20 +222,20 @@ void Sys_Printf (char *fmt, ...)
{
if (w > 0x800)
{
putc(0xe0 | ((w>>12)&0x0f), stdout);
putc(0x80 | ((w>>6)&0x3f), stdout);
putc(0xe0 | ((w>>12)&0x0f), out);
putc(0x80 | ((w>>6)&0x3f), out);
}
else
putc(0xc0 | ((w>>6)&0x1f), stdout);
putc(0x80 | (w&0x3f), stdout);
putc(0xc0 | ((w>>6)&0x1f), out);
putc(0x80 | (w&0x3f), out);
}
else
putc(w, stdout);
putc(w, out);
}
}
ApplyColour(CON_WHITEMASK);
fflush(stdout);
ApplyColour(out, CON_WHITEMASK);
fflush(out);
}
#else
void Sys_Printf (char *fmt, ...)
@ -736,9 +743,9 @@ dllhandle_t *Sys_LoadLibrary(const char *name, dllfunction_t *funcs)
lib = NULL;
if (!lib)
lib = dlopen (name, RTLD_LAZY);
lib = dlopen (name, RTLD_LOCAL|RTLD_LAZY);
if (!lib && !strstr(name, ".so"))
lib = dlopen (va("%s.so", name), RTLD_LAZY);
lib = dlopen (va("%s.so", name), RTLD_LOCAL|RTLD_LAZY);
if (!lib)
{
Con_DLPrintf(2,"%s\n", dlerror());
@ -884,6 +891,17 @@ char *Sys_ConsoleInput(void)
if (noconinput)
return NULL;
#if defined(__linux__) && defined(_DEBUG)
{
int fl = fcntl (STDIN_FILENO, F_GETFL, 0);
if (!(fl & FNDELAY))
{
fcntl(STDIN_FILENO, F_SETFL, fl | FNDELAY);
Sys_Printf(CON_WARNING "stdin flags became blocking - gdb bug?\n");
}
}
#endif
// if (!qrenderer)
{
if (!fgets(text, sizeof(text), stdin))
@ -1001,7 +1019,7 @@ int main (int c, const char **v)
noconinput = COM_CheckParm("-noconinput");
#ifndef __DJGPP__
if (!noconinput)
fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
fcntl(STDIN_FILENO, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
#endif
#ifndef CLIENTONLY

View File

@ -4432,7 +4432,377 @@ static qboolean QDECL Mod_LoadQ2Model (model_t *mod, void *buffer, size_t fsize)
#endif
#ifdef MODELFMT_MDX
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Kingpin model loading
//basically md2, but with toggleable subobjects and object bounding boxes (fixme: use those for hitmesh instead of the mesh itself)
typedef struct
{
float scale[3]; // multiply qbyte verts by this
float translate[3]; // then add this
char name[16]; // frame name from grabbing
dtrivertx_t verts[1]; // variable sized
} dmdxframe_t;
typedef struct
{
int cmd;
int obj;
struct dmdxcommandvert_s
{
float s, t;
int origvert;
} vert[1];
} dmdxcommand_t;
typedef struct
{
int magic;
int version;
int skinWidth;
int skinHeight;
int frameSize;
int numSkins;
int numVertices;
int numTriangles_Unusable;
int numGlCommands;
int numFrames;
int numSfxDefines_Unsupported;
int numSfxEntries_Unsupported;
int numSubObjects;
int offsetSkins;
int offsetTriangles_Unusable;
int offsetFrames;
int offsetGlCommands;
int offsetVertexInfo_Whatever;
int offsetSfxDefines_Unsupported;
int offsetSfxEntries_Unsupported;
int offsetBBoxFrames_HitmeshInstead;
int offsetMaybeST_Bugged;
int offsetEnd;
} dmdxheader_t;
#define MDX_IDENT ('I'<<0)+('D'<<8)+('P'<<16)+('X'<<24)
#define MDX_VERSION 4
#define Q2NUMVERTEXNORMALS 162
extern vec3_t bytedirs[Q2NUMVERTEXNORMALS];
#ifndef SERVERONLY
static void MDX_LoadSkins(galiasinfo_t *galias, model_t *mod, dmdxheader_t *pinmodel, char *skins)
{
int i;
skinframe_t *frames;
galiasskin_t *outskin = galias->ofsskins;
for (i = 0; i < LittleLong(pinmodel->numSkins); i++, outskin++)
{
frames = ZG_Malloc(&mod->memgroup, sizeof(*frames));
outskin->frame = frames;
outskin->numframes=1;
COM_CleanUpPath(skins); //blooming tanks.
Q_strncpyz(frames->shadername, skins, sizeof(frames->shadername));
outskin->skinwidth = 0;
outskin->skinheight = 0;
outskin->skinspeed = 0;
skins += MD2MAX_SKINNAME;
}
galias->numskins = LittleLong(pinmodel->numSkins);
}
#endif
#define MDX_MAX_TRIANGLES 4096
#define MDX_MAX_VERTS MDX_MAX_TRIANGLES*3
static int MDX_MatchVert(struct dmdxcommandvert_s *list, int *count, struct dmdxcommandvert_s *newvert)
{
int i;
for (i = 0; i < *count; i++)
{
if (list[i].origvert == newvert->origvert &&
list[i].s == newvert->s &&
list[i].t == newvert->t)
return i; //its a dupe!
}
if (i == MDX_MAX_VERTS)
return 0;
list[i] = *newvert;
*count+=1;
return i;
}
static qboolean QDECL Mod_LoadKingpinModel (model_t *mod, void *buffer, size_t fsize)
{
#ifndef SERVERONLY
vec2_t *st_array;
vec3_t *normals;
#endif
dmdxheader_t *pinmodel;
int version;
int i, j, subobj;
index_t *indexes;
vec3_t min;
vec3_t max;
galiaspose_t *pose;
galiasanimation_t *poutframe;
dmdxframe_t *pinframe;
int framesize;
vecV_t *verts;
dmdxcommand_t *pincmd, *pincmdend;
struct dmdxcommandvert_s tmpvert[MDX_MAX_VERTS];
int numverts;
struct
{
int newidx[3];
} tri[MDX_MAX_TRIANGLES];
int numtri;
int size;
galiasinfo_t *galias, *root;
mod->engineflags |= MDLF_NEEDOVERBRIGHT;
pinmodel = (dmdxheader_t *)buffer;
if (fsize < sizeof(*pinmodel))
{
Con_Printf (CON_ERROR "%s is truncated\n", mod->name);
return false;
}
version = LittleLong (pinmodel->version);
if (version != MDX_VERSION)
{
Con_Printf (CON_ERROR "%s has wrong version number (%i should be %i)\n",
mod->name, version, MDX_VERSION);
return false;
}
if (LittleLong(pinmodel->offsetEnd) != fsize)
{
Con_Printf (CON_ERROR "%s is truncated\n", mod->name);
return false;
}
if (LittleLong(pinmodel->numFrames) < 1 ||
LittleLong(pinmodel->numSkins) < 0 ||
LittleLong(pinmodel->numTriangles_Unusable) < 1 ||
LittleLong(pinmodel->numVertices) < 3 ||
LittleLong(pinmodel->skinHeight) < 1 ||
LittleLong(pinmodel->skinWidth) < 1 ||
LittleLong(pinmodel->numSubObjects) < 1)
{
Con_Printf(CON_ERROR "Model %s has an invalid quantity\n", mod->name);
return false;
}
mod->flags = 0;
mod->numframes = LittleLong(pinmodel->numFrames);
size = sizeof(galiasinfo_t)*pinmodel->numSubObjects
+ LittleLong(pinmodel->numFrames)*sizeof(galiasanimation_t)*pinmodel->numSubObjects
#ifndef SERVERONLY
+ LittleLong(pinmodel->numSkins)*sizeof(galiasskin_t)
#endif
;
root = galias = ZG_Malloc(&mod->memgroup, size);
#ifndef SERVERONLY
//skins
galias->ofsskins = (galiasskin_t*)((galiasanimation_t*)(galias+pinmodel->numSubObjects) + LittleLong(pinmodel->numFrames)*pinmodel->numSubObjects);
MDX_LoadSkins(galias, mod, pinmodel, ((char *)pinmodel+LittleLong(pinmodel->offsetSkins)));
#else
galias->numskins = LittleLong(pinmodel->numSkins);
#endif
ClearBounds (mod->mins, mod->maxs);
for (subobj = 0; subobj < pinmodel->numSubObjects; subobj++)
{
galias = &root[subobj];
Mod_DefaultMesh(galias, mod->name, subobj);
galias->ofsanimations = (galiasanimation_t*)(root+pinmodel->numSubObjects) + subobj*pinmodel->numFrames;
galias->ofsskins = root->ofsskins;
galias->numskins = root->numskins;
galias->shares_verts = subobj;
if (subobj > 0)
root[subobj-1].nextsurf = galias;
//process the strips+fans, and split the verts into the appropriate submesh
pincmd = (dmdxcommand_t *)((char *)pinmodel + LittleLong(pinmodel->offsetGlCommands));
pincmdend = (dmdxcommand_t *)((char *)pinmodel + LittleLong(pinmodel->offsetGlCommands) + LittleLong(pinmodel->numGlCommands)*4);
numverts = 0;
numtri = 0;
while (pincmd < pincmdend)
{
int n = LittleLong(pincmd->cmd);
if (!n)
break; //no more commands
if (n < 0)
{ //fan club
n = -n;
if (n > 2 && LittleLong(pincmd->obj) == subobj)
{
int first = MDX_MatchVert(tmpvert, &numverts, &pincmd->vert[0]);
int prev = MDX_MatchVert(tmpvert, &numverts, &pincmd->vert[1]);
for (i = 2; i < n && numtri < countof(tri); i++)
{
tri[numtri].newidx[0] = first;
tri[numtri].newidx[1] = prev;
tri[numtri].newidx[2] = prev = MDX_MatchVert(tmpvert, &numverts, &pincmd->vert[i]);
numtri++;
}
}
}
else
{ //stripper
if (n > 2 && LittleLong(pincmd->obj) == subobj)
{
int first = MDX_MatchVert(tmpvert, &numverts, &pincmd->vert[0]);
int prev = MDX_MatchVert(tmpvert, &numverts, &pincmd->vert[1]);
for (i = 2; i < n && numtri < countof(tri); i++)
{
tri[numtri].newidx[2] = MDX_MatchVert(tmpvert, &numverts, &pincmd->vert[i]);
if (i&1)
{
tri[numtri].newidx[0] = prev;
tri[numtri].newidx[1] = first;
}
else
{
tri[numtri].newidx[0] = first;
tri[numtri].newidx[1] = prev;
}
first = prev;
prev = tri[numtri].newidx[2];
if (tri[numtri].newidx[0] == tri[numtri].newidx[1] ||
tri[numtri].newidx[0] == tri[numtri].newidx[2] ||
tri[numtri].newidx[1] == tri[numtri].newidx[2])
continue; //degenerate... I doubt we'll see any though.
numtri++;
}
}
}
pincmd = (dmdxcommand_t*)&pincmd->vert[n];
}
for (i = 0; i < numverts; i++)
{ //might as well byteswap that stuff now...
tmpvert[i].origvert = LittleLong(tmpvert[i].origvert);
tmpvert[i].s = LittleFloat(tmpvert[i].s);
tmpvert[i].t = LittleFloat(tmpvert[i].t);
}
galias->numverts = numverts;
galias->numindexes = numtri*3;
indexes = ZG_Malloc(&mod->memgroup, galias->numindexes*sizeof(*indexes));
galias->ofs_indexes = indexes;
for (i = 0; i < numtri; i++, indexes+=3)
{
indexes[0] = tri[i].newidx[0];
indexes[1] = tri[i].newidx[1];
indexes[2] = tri[i].newidx[2];
}
// s and t vertices
#ifndef SERVERONLY
st_array = ZG_Malloc(&mod->memgroup, sizeof(*st_array)*(numverts));
galias->ofs_st_array = st_array;
for (j=0 ; j<numverts; j++)
{
st_array[j][0] = tmpvert[j].s;
st_array[j][1] = tmpvert[j].t;
}
#endif
//frames
poutframe = galias->ofsanimations;
framesize = LittleLong (pinmodel->frameSize);
size = sizeof(galiaspose_t) + sizeof(vecV_t)*numverts;
#ifndef SERVERONLY
size += 3*sizeof(vec3_t)*numverts;
#endif
size *= pinmodel->numFrames;
pose = (galiaspose_t *)ZG_Malloc(&mod->memgroup, size);
verts = (vecV_t*)(pose+pinmodel->numFrames);
#ifndef SERVERONLY
normals = (vec3_t*)(verts+pinmodel->numFrames*numverts);
#endif
for (i=0 ; i<LittleLong(pinmodel->numFrames) ; i++)
{
poutframe->poseofs = pose;
poutframe->numposes = 1;
galias->numanimations++;
#ifndef SERVERONLY
pose->ofsnormals = normals;
pose->ofssvector = &normals[galias->numverts];
pose->ofstvector = &normals[galias->numverts*2];
#endif
pinframe = ( dmdxframe_t * )( ( qbyte * )pinmodel + LittleLong (pinmodel->offsetFrames) + i * framesize );
Q_strncpyz(poutframe->name, pinframe->name, sizeof(poutframe->name));
for (j=0 ; j<3 ; j++)
{
pose->scale[j] = LittleFloat (pinframe->scale[j]);
pose->scale_origin[j] = LittleFloat (pinframe->translate[j]);
}
pose->ofsverts = verts;
for (j=0 ; j<numverts; j++)
{
// verts are all 8 bit, so no swapping needed
verts[j][0] = pose->scale_origin[0]+pose->scale[0]*pinframe->verts[tmpvert[j].origvert].v[0];
verts[j][1] = pose->scale_origin[1]+pose->scale[1]*pinframe->verts[tmpvert[j].origvert].v[1];
verts[j][2] = pose->scale_origin[2]+pose->scale[2]*pinframe->verts[tmpvert[j].origvert].v[2];
#ifndef SERVERONLY
VectorCopy(bytedirs[pinframe->verts[tmpvert[j].origvert].lightnormalindex], normals[j]);
#endif
}
VectorCopy ( pose->scale_origin, min );
VectorMA ( pose->scale_origin, 255, pose->scale, max );
AddPointToBounds ( min, mod->mins, mod->maxs );
AddPointToBounds ( max, mod->mins, mod->maxs );
poutframe++;
pose++;
verts += numverts;
#ifndef SERVERONLY
normals += numverts*3;
#endif
}
Mod_CompileTriangleNeighbours(mod, galias);
Mod_BuildTextureVectors(galias);
}
mod->radius = RadiusFromBounds(mod->mins, mod->maxs);
Mod_ClampModelSize(mod);
Mod_ParseModelEvents(mod, root->ofsanimations, root->numanimations);
mod->meshinfo = root;
mod->numframes = root->numanimations;
mod->type = mod_alias;
mod->funcs.NativeTrace = Mod_Trace;
return true;
}
#endif
@ -8807,6 +9177,9 @@ void Alias_Register(void)
#ifdef MD2MODELS
Mod_RegisterModelFormatMagic(NULL, "Quake2 Model (md2)", MD2IDALIASHEADER, Mod_LoadQ2Model);
#endif
#ifdef MODELFMT_MDX
Mod_RegisterModelFormatMagic(NULL, "Kingpin Model (mdx)", MDX_IDENT, Mod_LoadKingpinModel);
#endif
#ifdef MD3MODELS
Mod_RegisterModelFormatMagic(NULL, "Quake3 Model (md3)", MD3_IDENT, Mod_LoadQ3Model);
#endif

View File

@ -5228,7 +5228,7 @@ static void COM_ErrorMe_f(void)
#ifdef LOADERTHREAD
static void QDECL COM_WorkerCount_Change(cvar_t *var, char *oldvalue);
cvar_t worker_flush = CVARD("worker_flush", "1", "If set, process the entire load queue, loading stuff faster but at the risk of stalling the main thread.");
static cvar_t worker_count = CVARFCD("worker_count", "0", CVAR_NOTFROMSERVER, COM_WorkerCount_Change, "Specifies the number of worker threads to utilise.");
static cvar_t worker_count = CVARFCD("worker_count", "", CVAR_NOTFROMSERVER, COM_WorkerCount_Change, "Specifies the number of worker threads to utilise.");
static cvar_t worker_sleeptime = CVARFD("worker_sleeptime", "0", CVAR_NOTFROMSERVER, "Causes workers to sleep for a period of time after each job.");
#define WORKERTHREADS 16 //max
@ -5475,7 +5475,9 @@ static int COM_WorkerThread(void *arg)
thread->request = WR_NONE;
thread->ackseq = com_workeracksequence;
Sys_UnlockConditional(com_workercondition[group]);
Sys_LockConditional(com_workercondition[WG_MAIN]);
Sys_ConditionBroadcast(com_workercondition[WG_MAIN]); //try to wake up whoever wanted us to ack them
Sys_UnlockConditional(com_workercondition[WG_MAIN]);
Sys_LockConditional(com_workercondition[group]);
continue;
}

View File

@ -83,11 +83,13 @@
#define PSKMODELS //unreal's interchange format. Undesirable in terms of load times.
#define HALFLIFEMODELS //horrible format that doesn't interact well with the rest of FTE's code. Unusable tools (due to license reasons).
#define INTERQUAKEMODELS //Preferred model format, at least from an idealism perspective.
#define MODELFMT_MDX //kingpin's format (for hitboxes+geomsets).
#define RAGDOLL //ragdoll support. requires RBE support (via a plugin...).
//Image formats
#define IMAGEFMT_KTX //Khronos TeXture. common on gles3 devices for etc2 compression
#define IMAGEFMT_PKM //file format generally written by etcpack or android's etc1tool. doesn't support mips.
#define IMAGEFMT_ASTC //lame simple header around a single astc image. not needed for astc in ktx files etc. its better to use ktx files.
#define IMAGEFMT_PBM //pbm/ppm/pgm/pfm family formats.
#define IMAGEFMT_PSD //baselayer only.
#define IMAGEFMT_HDR //an RGBE format.
@ -104,6 +106,7 @@
#define DECOMPRESS_S3TC //allows bc1-3 to work even when drivers don't support it. This is probably only an issue on mobile chips. WARNING: not entirely sure if all patents expired yet...
#define DECOMPRESS_RGTC //bc4+bc5
#define DECOMPRESS_BPTC //bc6+bc7
#define DECOMPRESS_ASTC //ASTC, for drivers that don't support it properly.
// Game/Gamecode Support
#define CSQC_DAT

View File

@ -170,8 +170,9 @@ typedef struct console_s
conline_t *oldest;
conline_t *current; // line where next message will be printed
int x; // offset in current line for next print
int cr;
int cr; // last char printed was a carrage return so the next char printed will wipe the line.
conline_t *display; // bottom of console displays this line
float displayscroll; // to try to handle smoother scrolling.
int displayoffset; // horizontal offset
int vislines; // pixel lines
int linesprinted; // for notify times
@ -194,9 +195,9 @@ typedef struct console_s
conline_t *footerline; //temp text at the bottom of the console
conline_t *selstartline, *selendline;
unsigned int selstartoffset, selendoffset;
int mousedown[2]; //x,y position that the current buttons were clicked.
float mousedown[2]; //x,y position that the current buttons were clicked.
unsigned int buttonsdown;
int mousecursor[2]; //x,y
float mousecursor[2]; //x,y
float mousedowntime; //time mouse1 last went down, to detect double-clicks
struct console_s *next;

View File

@ -810,6 +810,7 @@ static int QDECL COM_Dir_List(const char *name, qofs_t size, time_t mtime, void
}
else if (!Q_strcasecmp(link, "bsp") || !Q_strcasecmp(link, "spr") || !Q_strcasecmp(link, "mdl") || !Q_strcasecmp(link, "md3") || !Q_strcasecmp(link, "iqm") ||
!Q_strcasecmp(link, "vvm") || !Q_strcasecmp(link, "psk") || !Q_strcasecmp(link, "dpm") || !Q_strcasecmp(link, "zym") || !Q_strcasecmp(link, "md5mesh") ||
!Q_strcasecmp(link, "mdx") || !Q_strcasecmp(link, "md2") ||
!Q_strcasecmp(link, "md5anim") || !Q_strcasecmp(link, "gltf") || !Q_strcasecmp(link, "glb") || !Q_strcasecmp(link, "ase") || !Q_strcasecmp(link, "lwo"))
Q_snprintfz(link, sizeof(link), "\\tip\\Open in Model Viewer\\modelviewer\\%s", name);
else if (!Q_strcasecmp(link, "qc") || !Q_strcasecmp(link, "src") || !Q_strcasecmp(link, "qh") || !Q_strcasecmp(link, "h") || !Q_strcasecmp(link, "c")
@ -2417,10 +2418,8 @@ typedef struct {
const char *puredesc;
unsigned int inheritflags;
} wildpaks_t;
static int QDECL FS_AddWildDataFiles (const char *descriptor, qofs_t size, time_t mtime, void *vparam, searchpathfuncs_t *funcs)
static void FS_AddSingleDataFile (const char *descriptor, wildpaks_t *param, searchpathfuncs_t *funcs)
{
wildpaks_t *param = vparam;
vfsfile_t *vfs;
searchpath_t *search;
searchpathfuncs_t *newpak;
@ -2434,7 +2433,7 @@ static int QDECL FS_AddWildDataFiles (const char *descriptor, qofs_t size, time_
for (search = com_searchpaths; search; search = search->next)
{
if (!Q_strcasecmp(search->logicalpath, pakfile)) //assumption: first member of structure is a char array
return true; //already loaded (base paths?)
return; //already loaded (base paths?)
}
newpak = FS_GetOldPath(param->oldpaths, pakfile, &keptflags);
@ -2448,16 +2447,16 @@ static int QDECL FS_AddWildDataFiles (const char *descriptor, qofs_t size, time_
{
fs_finds++;
if (!funcs->FindFile(funcs, &loc, descriptor, NULL))
return true; //not found..
return; //not found..
vfs = funcs->OpenVFS(funcs, &loc, "rb");
if (!vfs)
return true;
return;
}
newpak = param->OpenNew (vfs, funcs, descriptor, pakfile, "");
if (!newpak)
{
VFS_CLOSE(vfs);
return true;
return;
}
}
@ -2467,8 +2466,78 @@ static int QDECL FS_AddWildDataFiles (const char *descriptor, qofs_t size, time_
else
Q_strncpyz(purefile, descriptor, sizeof(purefile));
FS_AddPathHandle(param->oldpaths, purefile, pakfile, newpak, "", ((!Q_strncasecmp(descriptor, "pak", 3))?SPF_COPYPROTECTED:0)|keptflags|param->inheritflags, (unsigned int)-1);
}
typedef struct
{
//name table, to avoid too many reallocs
char *names;
size_t numnames;
size_t maxnames;
return true;
//file table, again to avoid excess reallocs
struct wilddatafile_s
{
size_t nameofs;
size_t size;
time_t mtime;
searchpathfuncs_t *source;
} *files;
size_t numfiles;
size_t maxfiles;
} filelist_t;
static int QDECL FS_FindWildDataFiles (const char *descriptor, qofs_t size, time_t mtime, void *vparam, searchpathfuncs_t *funcs)
{
filelist_t *list = vparam;
size_t name = list->numnames;
size_t file = list->numfiles;
size_t dlen = strlen(descriptor);
if (list->numnames + dlen+1 > list->maxnames)
Z_ReallocElements((void**)&list->names, &list->maxnames, list->numnames+dlen+1+8192, sizeof(*list->names));
strcpy(list->names + name, descriptor);
list->numnames += dlen+1;
if (list->numfiles + 1 > list->maxfiles)
Z_ReallocElements((void**)&list->files, &list->maxfiles, list->numfiles+1+128, sizeof(*list->files));
list->files[file].nameofs = name;
list->files[file].size = size;
list->files[file].mtime = mtime;
list->files[file].source = funcs;
list->numfiles += 1;
return true; //keep looking for more
}
static const char *qsortsucks;
static int QDECL FS_SortWildDataFiles(const void *va, const void *vb)
{
const struct wilddatafile_s *a=va, *b=vb;
const char *na=qsortsucks+a->nameofs, *nb=qsortsucks+b->nameofs;
//sort by modification time...
if (a->mtime != b->mtime && a->mtime && b->mtime)
return a->mtime > b->mtime;
//then fall back and sort by name
return strcasecmp(na, nb);
}
static void FS_LoadWildDataFiles (filelist_t *list, wildpaks_t *wp)
{
size_t f;
//sort them
qsortsucks = list->names;
qsort(list->files, list->numfiles, sizeof(*list->files), FS_SortWildDataFiles);
qsortsucks = NULL;
for (f = 0; f < list->numfiles; f++)
FS_AddSingleDataFile(list->names+list->files[f].nameofs, wp, list->files[f].source);
list->numfiles = list->numnames = 0;
Z_Free(list->files);
list->files = NULL;
Z_Free(list->names);
list->names = NULL;
list->maxfiles = list->maxnames = 0;
}
static searchpathfuncs_t *FS_OpenPackByExtension(vfsfile_t *f, searchpathfuncs_t *parent, const char *filename, const char *pakname)
@ -2645,6 +2714,7 @@ static void FS_AddDataFiles(searchpath_t **oldpaths, const char *purepath, const
vfsfile_t *vfs;
flocation_t loc;
wildpaks_t wp;
filelist_t list = {0};
Q_strncpyz(logicalpaths, logicalpath, sizeof(logicalpaths));
FS_CleanDir(logicalpaths, sizeof(logicalpaths));
@ -2680,7 +2750,7 @@ static void FS_AddDataFiles(searchpath_t **oldpaths, const char *purepath, const
if (loadstuff & (1<<j))
{
wp.OpenNew = searchpathformats[j].OpenNew;
FS_AddWildDataFiles(filename, 0, 0, &wp, search->handle);
FS_AddSingleDataFile(filename, &wp, search->handle);
}
break;
}
@ -2754,7 +2824,8 @@ static void FS_AddDataFiles(searchpath_t **oldpaths, const char *purepath, const
wp.OpenNew = searchpathformats[j].OpenNew;
Q_snprintfz (pakfile, sizeof(pakfile), "*.%s", extension);
search->handle->EnumerateFiles(search->handle, pakfile, FS_AddWildDataFiles, &wp);
search->handle->EnumerateFiles(search->handle, pakfile, FS_FindWildDataFiles, &list);
FS_LoadWildDataFiles(&list, &wp);
}
}

View File

@ -2194,6 +2194,8 @@ neterr_t NET_SendLoopPacket (int sock, int length, const void *data, netadr_t *t
{
int i;
loopback_t *loop;
if (!length && !data) //NET_EnsureRoute tests.
return NETERR_SENT;
sock &= 1;

View File

@ -275,9 +275,6 @@ void Sys_Sleep (double seconds)
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
#define STDIN 0
#define STDOUT 1
#define STDERR 2
typedef struct slaveserver_s
{
@ -386,10 +383,10 @@ pubsubserver_t *Sys_ForkServer(void)
if (!pid)
{ //this is the child
dup2(toslave[0], STDIN);
dup2(toslave[0], STDIN_FILENO);
close(toslave[1]);
close(toslave[0]);
dup2(tomaster[1], STDOUT);
dup2(tomaster[1], STDOUT_FILENO);
isClusterSlave = true;
@ -459,9 +456,9 @@ pubsubserver_t *Sys_ForkServer(void)
posix_spawn_file_actions_addclose(&action, toslave[1]);
posix_spawn_file_actions_addclose(&action, tomaster[0]);
posix_spawn_file_actions_adddup2(&action, toslave[0], STDIN);
posix_spawn_file_actions_adddup2(&action, tomaster[1], STDOUT);
// posix_spawn_file_actions_adddup2(&action, tomaster[1], STDERR);
posix_spawn_file_actions_adddup2(&action, toslave[0], STDIN_FILENO);
posix_spawn_file_actions_adddup2(&action, tomaster[1], STDOUT_FILENO);
// posix_spawn_file_actions_adddup2(&action, tomaster[1], STDERR_FILENO);
posix_spawn_file_actions_addclose(&action, toslave[0]);
posix_spawn_file_actions_addclose(&action, tomaster[1]);
@ -481,7 +478,7 @@ pubsubserver_t *Sys_ForkServer(void)
void Sys_InstructMaster(sizebuf_t *cmd)
{
write(STDOUT, cmd->data, cmd->cursize);
write(STDOUT_FILENO, cmd->data, cmd->cursize);
//FIXME: handle partial writes.
}
@ -490,6 +487,16 @@ void SSV_CheckFromMaster(void)
{
static char inbuffer[1024];
static int inbufsize;
#if defined(__linux__) && defined(_DEBUG)
int fl = fcntl (STDIN_FILENO, F_GETFL, 0);
if (!(fl & FNDELAY))
{
fcntl(STDIN_FILENO, F_SETFL, fl | FNDELAY);
Sys_Printf(CON_WARNING "stdin flags became blocking - gdb bug?\n");
}
#endif
for(;;)
{
if(inbufsize >= 2)
@ -517,7 +524,7 @@ void SSV_CheckFromMaster(void)
}
{
ssize_t avail = read(STDIN, inbuffer+inbufsize, sizeof(inbuffer)-inbufsize);
ssize_t avail = read(STDIN_FILENO, inbuffer+inbufsize, sizeof(inbuffer)-inbufsize);
if (!avail)
{ //eof
SV_FinalMessage("Cluster shut down\n");

View File

@ -1770,6 +1770,8 @@ void R_GAlias_GenerateBatches(entity_t *e, batch_t **batches)
for(surfnum=0; inf; inf=inf->nextsurf, surfnum++)
{
if (!inf->numindexes)
continue;
if (lod < inf->mindist || (inf->maxdist && lod >= inf->maxdist))
continue;

View File

@ -35,6 +35,8 @@ extern cvar_t gl_picmip2d;
extern cvar_t gl_compress;
extern cvar_t gl_smoothcrosshair;
extern cvar_t gl_texturemode, gl_texture_anisotropic_filtering;
cvar_t gl_blacklist_texture_compression = CVARFD("gl_blacklist_texture_compression", "0", CVAR_RENDERERLATCH, "When enabled, blocks recognition of all compressed-texture formats. Does NOT block support for gl3 texture types like e5bgr9 nor rgba16f.");
cvar_t gl_blacklist_generatemipmap = CVARFD("gl_blacklist_generatemipmap", "1", CVAR_RENDERERLATCH, "Self-generate mipmaps, instead of letting the graphics driver do it.");
float gl_anisotropy_factor;
@ -83,6 +85,10 @@ void GL_SetupFormats(void)
float ver = gl_config.glversion;
qboolean srgb = (gl_config.glversion >= (gl_config_gles?3.0:2.1)) || GL_CheckExtension("GL_EXT_texture_sRGB");
memset(&gl_config.formatinfo, 0, sizeof(gl_config.formatinfo));
memset(&sh_config.texfmt, 0, sizeof(sh_config.texfmt));
sh_config.hw_bc = sh_config.hw_etc = sh_config.hw_astc = 0;
if (gl_config_gles && ver >= 3.0 && ver <= 3.3)
ver = 3.3; //treat gles3.0 as desktop 3.3, they're roughly equivelent in feature set.
@ -90,7 +96,7 @@ void GL_SetupFormats(void)
bc1=bc2=bc3=true;
if ((!gl_config_gles && ver >= 3.0) || GL_CheckExtension("GL_ARB_texture_compression_rgtc") || GL_CheckExtension("GL_EXT_texture_compression_rgtc"))
bc45 = true;
if ((!gl_config.gles && ver >= 4.2) || GL_CheckExtension("GL_ARB_texture_compression_bptc"))
if ((!gl_config_gles && ver >= 4.2) || GL_CheckExtension("GL_ARB_texture_compression_bptc") || GL_CheckExtension("GL_EXT_texture_compression_bptc"))
bc67 = true;
if (bc45)
@ -119,6 +125,15 @@ void GL_SetupFormats(void)
bc2 |= GL_CheckExtension("GL_ANGLE_texture_compression_dxt3"); //WARNING: can only use these if mip0 is a multiple of 4
bc3 |= GL_CheckExtension("GL_ANGLE_texture_compression_dxt5");
#ifdef FTE_TARGET_WEB
if (GL_CheckExtension("GL_WEBGL_compressed_texture_s3tc"))
bc1 = bc2 = bc3 = true;
if (GL_CheckExtension("GL_WEBGL_compressed_texture_s3tc"))
bc1 = bc2 = bc3 = true;
#endif
/*else if (sh_config.texfmt[PTI_ETC2_RGB8A8])
{ //these are probably a bad choice...
tc_ru = GL_COMPRESSED_R11_EAC;
@ -271,6 +286,27 @@ void GL_SetupFormats(void)
}
}
//provide a cvar for ignoring all texture compression extensions.
//this is more so that I can debug fallbacks.
if (gl_blacklist_texture_compression.ival)
{
Con_Printf("gl_blacklist_texture_compression: driver/hardware texture compression is "CON_WARNING"blocked"CON_DEFAULT".\n");
return;
}
if (bc1&&bc2&&bc3)
{
if (bc45)
{
if (bc67)
sh_config.hw_bc = 3;
else
sh_config.hw_bc = 2;
}
else
sh_config.hw_bc = 1;
}
//block compresion formats.
if (bc1)
{
@ -309,12 +345,14 @@ void GL_SetupFormats(void)
glfmtb(PTI_BC7_RGBA_SRGB, GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB);
}
if (gl_config_gles && gl_config.glversion >= 3.0 && !sh_config.hw_bc)
sh_config.hw_etc = 2; //assume that mobile chips have actual support. the bc1 check prevents this from being true on desktop chips.
#ifdef FTE_TARGET_WEB
if (GL_CheckExtension("WEBGL_compressed_texture_etc"))
#else
if ((gl_config.gles && gl_config.glversion >= 3.0) || (!gl_config.gles && (gl_config.glversion >= 4.3 || GL_CheckExtension("GL_ARB_ES3_compatibility"))))
else if (GL_CheckExtension("GL_WEBGL_compressed_texture_etc"))
sh_config.hw_etc = 2; //full etc2+eac
#endif
{
if (sh_config.hw_etc>=2 || (!gl_config_gles && (gl_config.glversion >= 4.3 || GL_CheckExtension("GL_ARB_ES3_compatibility"))))
{ //note that desktop drivers will not necessarily support these in hardware, but are required to at least pretend that they do.
glfmtb(PTI_ETC1_RGB8, GL_COMPRESSED_RGB8_ETC2);
glfmtb(PTI_ETC2_RGB8, GL_COMPRESSED_RGB8_ETC2);
glfmtb(PTI_ETC2_RGB8A1, GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2);
@ -351,39 +389,73 @@ void GL_SetupFormats(void)
glfmtb(PTI_EAC_RG11, GL_COMPRESSED_RG11_EAC);
if (GL_CheckExtension("GL_OES_compressed_EAC_RG11_signed_texture"))
glfmtb(PTI_EAC_RG11_SNORM, GL_COMPRESSED_SIGNED_RG11_EAC);
if (gl_config.formatinfo[PTI_ETC2_RGB8].internalformat && gl_config.formatinfo[PTI_EAC_RG11].internalformat &&
gl_config.formatinfo[PTI_ETC2_RGB8A1].internalformat && gl_config.formatinfo[PTI_ETC2_RGB8A8].internalformat)
sh_config.hw_etc = 2;
else if (gl_config.formatinfo[PTI_ETC2_RGB8].internalformat || gl_config.formatinfo[PTI_ETC1_RGB8].internalformat)
sh_config.hw_etc = 1;
}
if (GL_CheckExtension("GL_KHR_texture_compression_astc_ldr") || (gl_config_gles && gl_config.glversion >= 3.2) || GL_CheckExtension("GL_ARB_ES3_2_compatibility"))
if (GL_CheckExtension("GL_OES_texture_compression_astc"))
sh_config.hw_astc = 3; //3d textures
else if (GL_CheckExtension("GL_KHR_texture_compression_astc_hdr"))
sh_config.hw_astc = 2; //hdr textures
else if (GL_CheckExtension("GL_KHR_texture_compression_astc_ldr"))
sh_config.hw_astc = 1; //ldr textures only.
#ifdef FTE_TARGET_WEB
else if (GL_CheckExtension("GL_WEBGL_compressed_texture_astc"))
sh_config.hw_astc = 1; //need to use js getSupportedProfiles() to find the profiles, which is outside of our scope
#endif
if (sh_config.hw_astc || (gl_config_gles && gl_config.glversion >= 3.2) || GL_CheckExtension("GL_ARB_ES3_2_compatibility"))
{ //astc ldr profile is a core part of gles 3.2
glfmtb(PTI_ASTC_4X4, GL_COMPRESSED_RGBA_ASTC_4x4_KHR);
//note that this does not necessarily mean the hardware itself supports it.
glfmtb(PTI_ASTC_4X4_LDR, GL_COMPRESSED_RGBA_ASTC_4x4_KHR);
glfmtb(PTI_ASTC_5X4_LDR, GL_COMPRESSED_RGBA_ASTC_5x4_KHR);
glfmtb(PTI_ASTC_5X5_LDR, GL_COMPRESSED_RGBA_ASTC_5x5_KHR);
glfmtb(PTI_ASTC_6X5_LDR, GL_COMPRESSED_RGBA_ASTC_6x5_KHR);
glfmtb(PTI_ASTC_6X6_LDR, GL_COMPRESSED_RGBA_ASTC_6x6_KHR);
glfmtb(PTI_ASTC_8X5_LDR, GL_COMPRESSED_RGBA_ASTC_8x5_KHR);
glfmtb(PTI_ASTC_8X6_LDR, GL_COMPRESSED_RGBA_ASTC_8x6_KHR);
glfmtb(PTI_ASTC_10X5_LDR, GL_COMPRESSED_RGBA_ASTC_10x5_KHR);
glfmtb(PTI_ASTC_10X6_LDR, GL_COMPRESSED_RGBA_ASTC_10x6_KHR);
glfmtb(PTI_ASTC_8X8_LDR, GL_COMPRESSED_RGBA_ASTC_8x8_KHR);
glfmtb(PTI_ASTC_10X8_LDR, GL_COMPRESSED_RGBA_ASTC_10x8_KHR);
glfmtb(PTI_ASTC_10X10_LDR, GL_COMPRESSED_RGBA_ASTC_10x10_KHR);
glfmtb(PTI_ASTC_12X10_LDR, GL_COMPRESSED_RGBA_ASTC_12x10_KHR);
glfmtb(PTI_ASTC_12X12_LDR, GL_COMPRESSED_RGBA_ASTC_12x12_KHR);
glfmtb(PTI_ASTC_4X4_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR);
glfmtb(PTI_ASTC_5X4, GL_COMPRESSED_RGBA_ASTC_5x4_KHR);
glfmtb(PTI_ASTC_5X4_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR);
glfmtb(PTI_ASTC_5X5, GL_COMPRESSED_RGBA_ASTC_5x5_KHR);
glfmtb(PTI_ASTC_5X5_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR);
glfmtb(PTI_ASTC_6X5, GL_COMPRESSED_RGBA_ASTC_6x5_KHR);
glfmtb(PTI_ASTC_6X5_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR);
glfmtb(PTI_ASTC_6X6, GL_COMPRESSED_RGBA_ASTC_6x6_KHR);
glfmtb(PTI_ASTC_6X6_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR);
glfmtb(PTI_ASTC_8X5, GL_COMPRESSED_RGBA_ASTC_8x5_KHR);
glfmtb(PTI_ASTC_8X5_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR);
glfmtb(PTI_ASTC_8X6, GL_COMPRESSED_RGBA_ASTC_8x6_KHR);
glfmtb(PTI_ASTC_8X6_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR);
glfmtb(PTI_ASTC_10X5, GL_COMPRESSED_RGBA_ASTC_10x5_KHR);
glfmtb(PTI_ASTC_10X5_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR);
glfmtb(PTI_ASTC_10X6, GL_COMPRESSED_RGBA_ASTC_10x6_KHR);
glfmtb(PTI_ASTC_10X6_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR);
glfmtb(PTI_ASTC_8X8, GL_COMPRESSED_RGBA_ASTC_8x8_KHR);
glfmtb(PTI_ASTC_8X8_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR);
glfmtb(PTI_ASTC_10X8, GL_COMPRESSED_RGBA_ASTC_10x8_KHR);
glfmtb(PTI_ASTC_10X8_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR);
glfmtb(PTI_ASTC_10X10, GL_COMPRESSED_RGBA_ASTC_10x10_KHR);
glfmtb(PTI_ASTC_10X10_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR);
glfmtb(PTI_ASTC_12X10, GL_COMPRESSED_RGBA_ASTC_12x10_KHR);
glfmtb(PTI_ASTC_12X10_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR);
glfmtb(PTI_ASTC_12X12, GL_COMPRESSED_RGBA_ASTC_12x12_KHR);
glfmtb(PTI_ASTC_12X12_SRGB, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR);
}
if (sh_config.hw_astc >= 2)
{ //astc hdr profile uses the same texture formats, which is kinda annoying...
glfmtb(PTI_ASTC_4X4_HDR, GL_COMPRESSED_RGBA_ASTC_4x4_KHR);
glfmtb(PTI_ASTC_5X4_HDR, GL_COMPRESSED_RGBA_ASTC_5x4_KHR);
glfmtb(PTI_ASTC_5X5_HDR, GL_COMPRESSED_RGBA_ASTC_5x5_KHR);
glfmtb(PTI_ASTC_6X5_HDR, GL_COMPRESSED_RGBA_ASTC_6x5_KHR);
glfmtb(PTI_ASTC_6X6_HDR, GL_COMPRESSED_RGBA_ASTC_6x6_KHR);
glfmtb(PTI_ASTC_8X5_HDR, GL_COMPRESSED_RGBA_ASTC_8x5_KHR);
glfmtb(PTI_ASTC_8X6_HDR, GL_COMPRESSED_RGBA_ASTC_8x6_KHR);
glfmtb(PTI_ASTC_10X5_HDR, GL_COMPRESSED_RGBA_ASTC_10x5_KHR);
glfmtb(PTI_ASTC_10X6_HDR, GL_COMPRESSED_RGBA_ASTC_10x6_KHR);
glfmtb(PTI_ASTC_8X8_HDR, GL_COMPRESSED_RGBA_ASTC_8x8_KHR);
glfmtb(PTI_ASTC_10X8_HDR, GL_COMPRESSED_RGBA_ASTC_10x8_KHR);
glfmtb(PTI_ASTC_10X10_HDR, GL_COMPRESSED_RGBA_ASTC_10x10_KHR);
glfmtb(PTI_ASTC_12X10_HDR, GL_COMPRESSED_RGBA_ASTC_12x10_KHR);
glfmtb(PTI_ASTC_12X12_HDR, GL_COMPRESSED_RGBA_ASTC_12x12_KHR);
}
}
/*
@ -414,6 +486,7 @@ void GLDraw_Init (void)
vid.flags &= ~VID_SRGBAWARE;
sh_config.can_genmips = qglGenerateMipmap && !gl_blacklist_generatemipmap.ival;
//figure out which extra features we can support on these drivers.
r_deluxemapping = r_deluxemapping_cvar.ival;
r_lightprepass = r_lightprepass_cvar.ival && sh_config.progs_supported;
@ -644,6 +717,8 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips)
qboolean compress;
qboolean storage = true;
unsigned int bb, bw, bh;
int levels = 0, genlevels;
int layers = 1;
if (gl_config.gles)
{
@ -662,17 +737,27 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips)
default:
case 0:
targ = GL_TEXTURE_2D;
layers = 1;
break;
case 1:
targ = GL_TEXTURE_3D;
layers = 1;
break;
case 2:
targ = GL_TEXTURE_CUBE_MAP_ARB;
layers = 1*6;
break;
case 3:
targ = GL_TEXTURE_2D_ARRAY;
layers = 1; //TODO
break;
}
genlevels = levels = mips->mipcount / layers;
if (!(tex->flags & IF_NOMIPMAP) && sh_config.can_genmips && gl_config.formatinfo[encoding].type && genlevels == 1 && mips->mip[0].data && mips->encoding != PTI_P8)
{
while ((mips->mip[0].width>>genlevels) || (mips->mip[0].height>>genlevels))
genlevels++;
}
GL_MTBind(0, targ, tex);
@ -690,6 +775,10 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips)
GL_MTBind(0, targ, tex);
}
//this is annoying.
if (mips->encoding >= PTI_ASTC_4X4_LDR && mips->encoding <= PTI_ASTC_12X12_LDR && gl_config.astc_decodeprecision)
qglTexParameteri(targ, GL_TEXTURE_ASTC_DECODE_PRECISION_EXT, GL_RGBA8);
if (tex->flags&IF_CLAMP)
{
if (gl_config.glversion < 1.2 && !gl_config_gles)
@ -739,13 +828,13 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips)
{
if (tex->flags & IF_MIPCAP)
{
qglTexParameteri(targ, GL_TEXTURE_BASE_LEVEL, min(nummips-1, gl_mipcap_min));
qglTexParameteri(targ, GL_TEXTURE_MAX_LEVEL, min(nummips-1, gl_mipcap_max));
qglTexParameteri(targ, GL_TEXTURE_BASE_LEVEL, min(genlevels-1, gl_mipcap_min));
qglTexParameteri(targ, GL_TEXTURE_MAX_LEVEL, min(genlevels-1, gl_mipcap_max));
}
else
{
qglTexParameteri(targ, GL_TEXTURE_BASE_LEVEL, 0);
qglTexParameteri(targ, GL_TEXTURE_MAX_LEVEL, nummips-1);
qglTexParameteri(targ, GL_TEXTURE_MAX_LEVEL, genlevels-1);
}
}
}
@ -822,10 +911,7 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips)
//FIXME: support array textures properly
if (qglTexStorage3D && storage)
{
if (tex->flags & IF_TEXTYPE)
qglTexStorage3D(targ, nummips/countof(cubeface), ifmt, mips->mip[0].width, mips->mip[0].height, mips->mip[0].depth);
else
qglTexStorage3D(targ, nummips, ifmt, mips->mip[0].width, mips->mip[0].height, mips->mip[0].depth);
qglTexStorage3D(targ, genlevels, ifmt, mips->mip[0].width, mips->mip[0].height, mips->mip[0].depth);
for (i = 0; i < nummips; i++)
{
@ -848,15 +934,15 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips)
qglCompressedTexImage3D (targ, i, ifmt, mips->mip[i].width, mips->mip[i].height, mips->mip[0].depth, 0, mips->mip[i].datasize, mips->mip[i].data);
}
}
if (genlevels > levels)
qglGenerateMipmap(targ);
}
else
{
if (qglTexStorage2D && storage)
{ //FIXME: destroy the old texture
if (tex->flags & IF_TEXTYPE)
qglTexStorage2D(targ, nummips/countof(cubeface), ifmt, mips->mip[0].width, mips->mip[0].height);
else
qglTexStorage2D(targ, nummips, ifmt, mips->mip[0].width, mips->mip[0].height);
qglTexStorage2D(targ, genlevels, ifmt, mips->mip[0].width, mips->mip[0].height);
for (i = 0; i < nummips; i++)
{
@ -902,6 +988,9 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips)
}
}
if (genlevels > levels)
qglGenerateMipmap(targ);
#ifdef IMAGEFMT_KTX
if (compress && gl_compress.ival>1 && gl_config.formatinfo[encoding].type)
{
@ -944,33 +1033,33 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips)
case GL_COMPRESSED_SIGNED_R11_EAC: out.encoding = PTI_EAC_R11_SNORM; break;
case GL_COMPRESSED_RG11_EAC: out.encoding = PTI_EAC_RG11; break;
case GL_COMPRESSED_SIGNED_RG11_EAC: out.encoding = PTI_EAC_RG11_SNORM; break;
case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: out.encoding = PTI_ASTC_4X4; break;
case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: out.encoding = PTI_ASTC_4X4_HDR; break; //play it safe and assume hdr.
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: out.encoding = PTI_ASTC_4X4_SRGB; break;
case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: out.encoding = PTI_ASTC_5X4; break;
case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: out.encoding = PTI_ASTC_5X4_HDR; break;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: out.encoding = PTI_ASTC_5X4_SRGB; break;
case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: out.encoding = PTI_ASTC_5X5; break;
case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: out.encoding = PTI_ASTC_5X5_HDR; break;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: out.encoding = PTI_ASTC_5X5_SRGB; break;
case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: out.encoding = PTI_ASTC_6X5; break;
case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: out.encoding = PTI_ASTC_6X5_HDR; break;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: out.encoding = PTI_ASTC_6X5_SRGB; break;
case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: out.encoding = PTI_ASTC_6X6; break;
case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: out.encoding = PTI_ASTC_6X6_HDR; break;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: out.encoding = PTI_ASTC_6X6_SRGB; break;
case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: out.encoding = PTI_ASTC_8X5; break;
case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: out.encoding = PTI_ASTC_8X5_HDR; break;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: out.encoding = PTI_ASTC_8X5_SRGB; break;
case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: out.encoding = PTI_ASTC_8X6; break;
case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: out.encoding = PTI_ASTC_8X6_HDR; break;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: out.encoding = PTI_ASTC_8X6_SRGB; break;
case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: out.encoding = PTI_ASTC_10X5; break;
case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: out.encoding = PTI_ASTC_10X5_HDR; break;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: out.encoding = PTI_ASTC_10X5_SRGB; break;
case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: out.encoding = PTI_ASTC_10X6; break;
case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: out.encoding = PTI_ASTC_10X6_HDR; break;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: out.encoding = PTI_ASTC_10X6_SRGB; break;
case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: out.encoding = PTI_ASTC_8X8; break;
case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: out.encoding = PTI_ASTC_8X8_HDR; break;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: out.encoding = PTI_ASTC_8X8_SRGB; break;
case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: out.encoding = PTI_ASTC_10X8; break;
case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: out.encoding = PTI_ASTC_10X8_HDR; break;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: out.encoding = PTI_ASTC_10X8_SRGB; break;
case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: out.encoding = PTI_ASTC_10X10; break;
case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: out.encoding = PTI_ASTC_10X10_HDR; break;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: out.encoding = PTI_ASTC_10X10_SRGB; break;
case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: out.encoding = PTI_ASTC_12X10; break;
case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: out.encoding = PTI_ASTC_12X10_HDR; break;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: out.encoding = PTI_ASTC_12X10_SRGB; break;
case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: out.encoding = PTI_ASTC_12X12; break;
case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: out.encoding = PTI_ASTC_12X12_HDR; break;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: out.encoding = PTI_ASTC_12X12_SRGB; break;
}

View File

@ -28,6 +28,8 @@ cvar_t mod_terrain_sundir = CVARD("mod_terrain_sundir", "0.4 0.7 2", "The direct
cvar_t mod_terrain_ambient = CVARD("mod_terrain_ambient", "0.5", "Proportion of ambient light.");
cvar_t mod_terrain_shadows = CVARD("mod_terrain_shadows", "0", "Cast rays to determine whether parts of the terrain should be in shadow.");
cvar_t mod_terrain_shadow_dist = CVARD("mod_terrain_shadow_dist", "2048", "How far rays should be cast in order to look for occlusing geometry.");
cvar_t mod_terrain_brushlights = CVARD("mod_map_lights", "0", "Calculates lighting on brushes/patches.");
cvar_t mod_terrain_brushtexscale = CVARD("mod_map_texscale", "1", "Defines the scale of texture texels. Use 1 for quake+quake2 maps, and 0.5 for quake3 maps.");
enum
{
@ -5546,7 +5548,8 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
if (mod->submodelof)
mod = mod->submodelof;
hm->entsdirty = false;
LightReloadEntities(hm->relightcontext, Mod_GetEntitiesString(mod), true);
if (hm->relightcontext)
LightReloadEntities(hm->relightcontext, Mod_GetEntitiesString(mod), true);
//FIXME: figure out some way to hint this without having to relight the entire frigging world.
for (bt = hm->brushtextures; bt; bt = bt->next)
@ -5835,11 +5838,15 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
const miptex_t *tx = NULL;
#endif
if (!Q_strcasecmp(bt->shadername, "clip") || !Q_strcasecmp(bt->shadername, "hint") || !Q_strcasecmp(bt->shadername, "skip"))
bt->shader = R_RegisterShader(bt->shadername, SUF_LIGHTMAP, "{\nsurfaceparm nodraw\n}");
else
bt->shader = R_RegisterCustom (bt->shadername, SUF_LIGHTMAP, Shader_DefaultBSPQ1, NULL);
// bt->shader = R_RegisterShader_Lightmap(bt->shadername);
bt->shader = R_RegisterCustom (va("textures/%s", bt->shadername), SUF_LIGHTMAP, NULL, NULL);
if (!bt->shader)
{
if (!Q_strcasecmp(bt->shadername, "clip") || !Q_strcasecmp(bt->shadername, "hint") || !Q_strcasecmp(bt->shadername, "skip"))
bt->shader = R_RegisterShader(bt->shadername, SUF_LIGHTMAP, "{\nsurfaceparm nodraw\n}");
else
bt->shader = R_RegisterCustom (bt->shadername, SUF_LIGHTMAP, Shader_DefaultBSPQ1, NULL);
// bt->shader = R_RegisterShader_Lightmap(bt->shadername);
}
if (!Q_strncasecmp(bt->shadername, "sky", 3) && tx)
R_InitSky (bt->shader, bt->shadername, (qbyte*)tx + tx->offsets[0], tx->width, tx->height);
@ -5871,8 +5878,8 @@ void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
if (w<1) w = 64;
if (h<1) h = 64;
scale[0] = 1.0/w; //I hate needing this.
scale[1] = 1.0/h;
scale[0] = mod_terrain_brushtexscale.value/w; //I hate needing this.
scale[1] = mod_terrain_brushtexscale.value/h;
while(bt->batches)
{
@ -7411,7 +7418,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
#ifdef RUNTIMELIGHTING
hm->entsdirty = true;
hm->relightcontext = LightStartup(NULL, mod, false, false);
hm->relightcontext = mod_terrain_brushlights.ival?LightStartup(NULL, mod, mod_terrain_brushlights.ival>1, false):NULL;
hm->lightthreadmem = BZ_Malloc(lightthreadctxsize);
hm->inheritedlightthreadmem = false;
#endif
@ -8480,6 +8487,8 @@ void Terr_Init(void)
Cvar_Register(&mod_terrain_ambient, "Terrain");
Cvar_Register(&mod_terrain_shadows, "Terrain");
Cvar_Register(&mod_terrain_shadow_dist, "Terrain");
Cvar_Register(&mod_terrain_brushlights, "Terrain");
Cvar_Register(&mod_terrain_brushtexscale, "Terrain");
#endif
Mod_RegisterModelFormatText(NULL, "FTE Heightmap Map (hmp)", "terrain", Terr_LoadTerrainModel);

View File

@ -681,8 +681,12 @@ static void Shader_ParseFunc (shader_t *shader, char **ptr, shaderfunc_t *func)
func->type = SHADER_FUNC_INVERSESAWTOOTH;
else if (!Q_stricmp (token, "noise"))
func->type = SHADER_FUNC_NOISE;
else if (!Q_stricmp (token, "distanceramp")) //QFusion
else
{
if (!Q_stricmp (token, "distanceramp")) //QFusion
;
else
Con_Printf("Shader_ParseFunc: %s: unknown func %s\n", shader->name, token);
func->type = SHADER_FUNC_CONSTANT; //not supported...
Shader_ParseFloat (shader, ptr, 0);
Shader_ParseFloat (shader, ptr, 0);

View File

@ -2939,7 +2939,7 @@ static void Sh_DrawBrushModelShadow(dlight_t *dl, entity_t *e)
//front face
qglVertexPointer(3, GL_FLOAT, sizeof(vecV_t), surf->mesh->xyz_array);
qglDrawArrays(GL_POLYGON, 0, surf->mesh->numvertexes);
// qglDrawRangeElements(GL_TRIANGLES, 0, surf->mesh->numvertexes, surf->mesh->numindexes, GL_INDEX_TYPE, surf->mesh->indexes);
// qglDrawRangeElements(GL_TRIANGLES, 0, surf->mesh->numvertexes-1, surf->mesh->numindexes, GL_INDEX_TYPE, surf->mesh->indexes);
RQuantAdd(RQUANT_SHADOWINDICIES, surf->mesh->numvertexes);
for (v = 0; v < surf->mesh->numvertexes; v++)

View File

@ -50,6 +50,7 @@ void (APIENTRY *qglEnable) (GLenum cap);
void (APIENTRY *qglFinish) (void);
void (APIENTRY *qglFlush) (void);
void (APIENTRY *qglGenTextures) (GLsizei n, GLuint *textures);
void (APIENTRY *qglGenerateMipmap)(GLenum target);
void (APIENTRY *qglGetBooleanv) (GLenum pname, GLboolean *params);
GLenum (APIENTRY *qglGetError) (void);
void (APIENTRY *qglGetFloatv) (GLenum pname, GLfloat *params);
@ -862,6 +863,8 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
gl_config.arb_texture_compression = true;
}
#endif
gl_config.astc_decodeprecision = GL_CheckExtension("GL_EXT_texture_compression_astc_decode_mode");
/*
if (GL_CheckExtension("GL_EXT_depth_bounds_test"))
qglDepthBoundsEXT = (void *)getglext("glDepthBoundsEXT");
@ -3349,6 +3352,11 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name))
GL_CheckExtensions (getglfunction);
if (gl_config.glversion >= 3.0)
qglGenerateMipmap = (void *)getglext("glGenerateMipmap");
else
qglGenerateMipmap = NULL;
#ifndef FTE_TARGET_WEB
if (!gl_config.gles)
{

View File

@ -195,7 +195,7 @@ qboolean R_DrawSkyroom(shader_t *skyshader)
//q3 mustn't mask sky (breaks q3map2's invisible skyportals), whereas q1 must (or its a cheat). halflife doesn't normally expect masking.
//we also MUST mask any sky inside skyrooms, or you'll see all the entities outside of the skyroom through the room's own sky (q3map2 skyportals are hopefully irrelevant in this case).
#define SKYMUSTBEMASKED (r_worldentity.model->fromgame != fg_quake3 || ((r_refdef.flags & RDF_DISABLEPARTICLES) && !r_ignoreentpvs.ival))
#define SKYMUSTBEMASKED (r_worldentity.model->fromgame != fg_quake3 || ((r_refdef.flags & RDF_DISABLEPARTICLES) && r_ignoreentpvs.ival))
/*
=================

View File

@ -235,6 +235,7 @@ typedef struct {
qboolean arb_texture_env_dot3;
qboolean arb_texture_compression; //means we support dynamic compression, rather than any specific compressed texture formats
qboolean astc_decodeprecision; //means we can tell the gpu that our astc textures actually are ldr.
qboolean geometryshaders;
qboolean arb_tessellation_shader;
@ -652,6 +653,7 @@ extern void (APIENTRY *qglFinish) (void);
extern void (APIENTRY *qglFlush) (void);
extern void (APIENTRY *qglFrontFace) (GLenum mode);
extern void (APIENTRY *qglGenTextures) (GLsizei n, GLuint *textures);
extern void (APIENTRY *qglGenerateMipmap)(GLenum target);
extern void (APIENTRY *qglGetBooleanv) (GLenum pname, GLboolean *params);
extern GLenum (APIENTRY *qglGetError) (void);
extern void (APIENTRY *qglGetFloatv) (GLenum pname, GLfloat *params);

View File

@ -682,9 +682,11 @@ typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei
#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F
#endif /* GL_EXT_texture_sRGB */
#ifndef GL_RGB9_E5
#define GL_RGB9_E5 0x8C3D /*opengl 3.0*/
#endif
#ifndef GL_RG
#define GL_RG 0x8227
#define GL_RGB9_E5 0x8C3D /*opengl 3.0*/
#define GL_R8 0x8229 /*opengl 3.0*/
#define GL_R16 0x822A /*opengl 3.0*/
#define GL_RG8 0x822B /*opengl 3.0*/
@ -811,7 +813,9 @@ typedef void (APIENTRY * PFNGLUNLOCKARRAYSEXTPROC) (void);
#endif
#ifndef GL_EXT_texture_compression_astc_decode_mode
#define GL_TEXTURE_ASTC_DECODE_PRECISION_EXT 0x8F69
#endif
#ifndef GL_EXT_framebuffer_object
#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506

File diff suppressed because it is too large Load Diff

View File

@ -542,6 +542,12 @@ typedef struct programshared_s
unsigned int supportedpermutations;
unsigned char *cvardata;
unsigned int cvardatasize;
int shaderver; //glsl version
char *preshade; //general prefixed #defines
char *shadertext; //the glsl text
unsigned char failed[(PERMUTATIONS+7)/8]; //so we don't try recompiling endlessly
struct programpermu_s *permu[PERMUTATIONS]; //set once compiled.
#ifdef VKQUAKE
qVkShaderModule vert; //for slightly faster regeneration
qVkShaderModule frag;
@ -549,14 +555,6 @@ typedef struct programshared_s
qVkDescriptorSetLayout desclayout;
struct pipeline_s *pipelines;
#endif
#define DELAYEDSHADERCOMPILE
#ifdef DELAYEDSHADERCOMPILE
int shaderver; //glsl version
char *preshade; //general prefixed #defines
char *shadertext; //the glsl text
unsigned char failed[(PERMUTATIONS+7)/8]; //so we don't try recompiling endlessly
struct programpermu_s *permu[PERMUTATIONS]; //set once compiled.
#endif
} program_t;
typedef struct {
@ -798,6 +796,7 @@ typedef struct
unsigned int maxver; //highest glsl version usable
unsigned int max_gpu_bones; //max number of bones supported by uniforms.
int hw_bc, hw_etc, hw_astc; //these are set only if the hardware actually supports the format, and not if we think the drivers are software-decoding them (unlike texfmt).
qboolean texfmt[PTI_MAX]; //which texture formats are supported (renderable not implied)
unsigned int texture2d_maxsize; //max size of a 2d texture
unsigned int texture3d_maxsize; //max size of a 3d texture
@ -812,6 +811,7 @@ typedef struct
qboolean env_add;
qboolean can_mipcap; //gl1.2+
qboolean can_mipbias; //gl1.4+
qboolean can_genmips; //gl3.0+
qboolean havecubemaps; //since gl1.3, so pretty much everyone will have this... should probably only be set if we also have seamless or clamp-to-edge.
void (*pDeleteProg) (program_t *prog);
@ -841,6 +841,7 @@ extern const struct sh_defaultsamplers_s
#ifdef VKQUAKE
qboolean VK_LoadBlob(program_t *prog, void *blobdata, const char *name);
void VK_RegisterVulkanCvars(void);
#endif
#ifdef GLQUAKE

View File

@ -2743,7 +2743,7 @@ retry:
if (!trysleft) //the progs exists, let's just be happy about it.
externs->Printf("Progs is out of date and uncompilable\n");
if (externs->CheckHeaderCrc && !externs->CheckHeaderCrc(&progfuncs->funcs, prinst.pr_typecurrent, pr_progs->crc))
if (externs->CheckHeaderCrc && !externs->CheckHeaderCrc(&progfuncs->funcs, prinst.pr_typecurrent, pr_progs->crc, filename))
{
// externs->Printf ("%s system vars have been modified, progdefs.h is out of date\n", filename);
PRHunkFree(progfuncs, hmark);

View File

@ -212,7 +212,7 @@ typedef struct progexterns_s {
int (VARGS *DPrintf) (const char *, ...) LIKEPRINTF(1);
void (VARGS *Sys_Error) (const char *, ...) LIKEPRINTF(1);
void (VARGS *Abort) (char *, ...) LIKEPRINTF(1);
pbool (PDECL *CheckHeaderCrc) (pubprogfuncs_t *inst, progsnum_t idx, int crc);
pbool (PDECL *CheckHeaderCrc) (pubprogfuncs_t *inst, progsnum_t idx, int crc, const char *filename);
void (PDECL *entspawn) (struct edict_s *ent, int loading); //ent has been spawned, but may not have all the extra variables (that may need to be set) set
pbool (PDECL *entcanfree) (struct edict_s *ent); //return true to stop ent from being freed

View File

@ -711,7 +711,7 @@ static qboolean QDECL SVPR_Event_ContentsTransition(world_t *w, wedict_t *ent, i
#define H2MP_PROGHEADER_CRC 26905 //hexen2 mission pack uses slightly different defs... *sigh*...
#define H2DEMO_PROGHEADER_CRC 14046 //I'm guessing this is from the original release or something
pbool PDECL PR_SSQC_CheckHeaderCrc(pubprogfuncs_t *inst, progsnum_t idx, int crc)
pbool PDECL PR_SSQC_CheckHeaderCrc(pubprogfuncs_t *inst, progsnum_t idx, int crc, const char *filename)
{
progstype_t modtype;
if (crc == QW_PROGHEADER_CRC)
@ -734,7 +734,10 @@ pbool PDECL PR_SSQC_CheckHeaderCrc(pubprogfuncs_t *inst, progsnum_t idx, int crc
progstype = modtype;
//if the new one differs from the main module, reject it, unless it has crc 0, which we'll allow as a universal mutator (good luck guessing the correct arguments, but hey).
if (progstype != modtype && crc != 0)
{
Con_Printf("Unable to load \"%s\" due to mismatched gametype/progdefs\n", filename);
return false;
}
return true;
}
static void *PDECL SSQC_PRReadFile (const char *path, qbyte *(PDECL *buf_get)(void *buf_ctx, size_t size), void *buf_ctx, size_t *size, pbool issource)

View File

@ -1260,10 +1260,12 @@ qboolean MSV_ClusterLoginSQLResult(queryrequest_t *req, int firstrow, int numrow
}
#endif
qboolean MSV_IgnoreSQLResult(queryrequest_t *req, int firstrow, int numrows, int numcols, qboolean eof)
#if 0
static qboolean MSV_IgnoreSQLResult(queryrequest_t *req, int firstrow, int numrows, int numcols, qboolean eof)
{
return false;
}
#endif
void MSV_OpenUserDatabase(void)
{
#if 0

View File

@ -1132,7 +1132,7 @@ static void SVC_Status (void)
int ping;
int top, bottom;
char frags[64];
char *skin, *team, *botpre;
char *skin, *team, *botpre, *specpre;
int slots=0;
@ -1170,6 +1170,7 @@ static void SVC_Status (void)
else
botpre = "";
specpre = "";
if (cl->spectator)
{ //silly mvdsv stuff
if (displayflags & STATUS_SPECTATORS_AS_PLAYERS)
@ -1181,7 +1182,7 @@ static void SVC_Status (void)
{
ping = -ping;
sprintf(frags, "%i", -9999);
name = va("\\s\\%s", name);
specpre = "\\s\\";
}
}
else
@ -1189,15 +1190,15 @@ static void SVC_Status (void)
if (displayflags & STATUS_SHOWTEAMS)
{
Con_Printf ("%i %s %i %i \"%s%s\" \"%s\" %i %i \"%s\"\n", cl->userid,
Con_Printf ("%i %s %i %i \"%s%s%s\" \"%s\" %i %i \"%s\"\n", cl->userid,
frags, (int)(realtime - cl->connection_started)/60,
ping, botpre, name, skin, top, bottom, team);
ping, specpre, botpre, name, skin, top, bottom, team);
}
else
{
Con_Printf ("%i %s %i %i \"%s%s\" \"%s\" %i %i\n", cl->userid,
Con_Printf ("%i %s %i %i \"%s%s%s\" \"%s\" %i %i\n", cl->userid,
frags, (int)(realtime - cl->connection_started)/60,
ping, botpre, name, skin, top, bottom);
ping, specpre, botpre, name, skin, top, bottom);
}
}
else

View File

@ -13,6 +13,7 @@
!!cvardf r_tessellation_level=5
!!samps !EIGHTBIT diffuse normalmap specular fullbright upper lower reflectmask reflectcube
!!samps =EIGHTBIT paletted 1
!!samps =OCCLUDE occlusion
//!!permu VC // adds rgba vertex colour multipliers
//!!permu SPECULAR // auto-added when gl_specular>0
//!!permu OFFSETMAPPING // auto-added when r_glsl_offsetmapping is set
@ -21,6 +22,7 @@
//!!permu SG // specularmap is rgb:F0, a:Roughness (instead of exponent)
//!!permu PBR // an attempt at pbr logic (enabled from ORM or SG)
//!!permu NOOCCLUDE // ignores the use of ORM's occlusion... yeah, stupid.
//!!permu OCCLUDE // use an explicit occlusion texturemap (separate from roughness+metalness).
//!!permu EIGHTBIT // uses software-style paletted colourmap lookups
//!!permu ALPHATEST // if defined, this is the required alpha level (more versatile than doing it at the q3shader level)
@ -329,12 +331,12 @@ void main ()
#define ambientrgb (specrgb+col.rgb)
vec3 specrgb = mix(vec3(dielectricSpecular), col.rgb, metalness);
col.rgb = col.rgb * (1.0 - dielectricSpecular) * (1.0-metalness);
#elif defined(SG) //pbr-style specular+glossiness
#elif defined(SG) //pbr-style specular+glossiness, without occlusion
//occlusion needs to be baked in. :(
#define roughness (1.0-specs.a)
#define gloss (specs.a)
#define specrgb specs.rgb
#define ambientrgb (specs.rgb+col.rgb)
#define ambientrgb (specrgb+col.rgb)
#else //blinn-phong
#define roughness (1.0-specs.a)
#define gloss specs.a
@ -378,7 +380,9 @@ void main ()
col.rgb += texture2D(s_reflectmask, tc).rgb * textureCube(s_reflectcube, rtc).rgb;
#endif
#if defined(occlusion) && !defined(NOOCCLUDE)
#ifdef OCCLUDE
col.rgb *= texture2D(s_occlusion, tc).r;
#elif defined(occlusion) && !defined(NOOCCLUDE)
col.rgb *= occlusion;
#endif
col *= light * e_colourident;

View File

@ -8,8 +8,8 @@
!!samps diffuse normalmap specular fullbright lightmap
!!samps deluxmap reflectmask reflectcube
!!argb vertexlit=0
!!samps paletted 1
!!argb eightbit=0
//!!samps =EIGHTBIT paletted 1
//!!argb eightbit=0
!!argf mask=1.0
!!argb masklt=false
!!permu FOG
@ -114,7 +114,7 @@ void main ()
lightmaps += texture2D(s_lightmap3, lm3).rgb * e_lmscale[3].rgb;
}
#else
if (arg_eightbit)
/*if (arg_eightbit)
{
//optional: round the lightmap coords to ensure all pixels within a texel have different lighting values either. it just looks wrong otherwise.
//don't bother if its lightstyled, such cases will have unpredictable correlations anyway.
@ -122,7 +122,7 @@ void main ()
vec2 nearestlm0 = floor(lm0 * 256.0*8.0)/(256.0*8.0);
lightmaps = (texture2D(s_lightmap, nearestlm0) * e_lmscale).rgb;
}
else
else*/
lightmaps = (texture2D(s_lightmap, lm0) * e_lmscale).rgb;
//modulate by the bumpmap dot light
if (DELUXE)
@ -165,7 +165,7 @@ void main ()
gl_FragColor.rgb += texture2D(s_reflectmask, tc).rgb * textureCube(s_reflectcube, rtc).rgb;
}
if (arg_eightbit)
/*if (arg_eightbit)
{
//FIXME: with this extra flag, half the permutations are redundant.
lightmaps *= 0.5; //counter the fact that the colourmap contains overbright values and logically ranges from 0 to 2 intead of to 1.
@ -175,7 +175,7 @@ void main ()
gl_FragColor.g = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.g)).g; //its not very softwarey, but re-palettizing is ugly.
gl_FragColor.b = texture2D(s_colourmap, vec2(pal, 1.0-lightmaps.b)).b; //without lits, it should be identical.
}
else
else*/
{
//now we have our diffuse+specular terms, modulate by lightmap values.
gl_FragColor.rgb *= lightmaps.rgb;

View File

@ -6,18 +6,45 @@
#include "renderque.h" //is anything still using this?
extern qboolean vid_isfullscreen;
extern cvar_t vk_submissionthread;
extern cvar_t vk_debug;
extern cvar_t vk_dualqueue;
extern cvar_t vk_busywait;
extern cvar_t vk_waitfence;
extern cvar_t vk_nv_glsl_shader;
extern cvar_t vk_khr_get_memory_requirements2;
extern cvar_t vk_khr_dedicated_allocation;
extern cvar_t vk_khr_push_descriptor;
extern cvar_t vk_amd_rasterization_order;
extern cvar_t vk_usememorypools;
cvar_t vk_stagingbuffers = CVARFD ("vk_stagingbuffers", "", CVAR_RENDERERLATCH, "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(niform), e(lements), v(ertex), 0(none).");
static 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.");
static cvar_t vk_debug = CVARFD("vk_debug", "0", CVAR_VIDEOLATCH, "Register a debug handler to display driver/layer messages. 2 enables the standard validation layers.");
static cvar_t vk_dualqueue = CVARFD("vk_dualqueue", "", CVAR_VIDEOLATCH, "Attempt to use a separate queue for presentation. Blank for default.");
static cvar_t vk_busywait = CVARD ("vk_busywait", "", "Force busy waiting until the GPU finishes doing its thing.");
static cvar_t vk_waitfence = CVARD ("vk_waitfence", "", "Waits on fences, instead of semaphores. This is more likely to result in gpu stalls while the cpu waits.");
static cvar_t vk_usememorypools = CVARFD("vk_usememorypools", "", CVAR_VIDEOLATCH, "Allocates memory pools for sub allocations. Vulkan has a limit to the number of memory allocations allowed so this should always be enabled, however at this time FTE is unable to reclaim pool memory, and would require periodic vid_restarts to flush them.");
static cvar_t vk_nv_glsl_shader = CVARFD("vk_loadglsl", "", CVAR_VIDEOLATCH, "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 glsl compile errors). Don't forget to do a vid_restart after.");
static cvar_t vk_khr_get_memory_requirements2 = CVARFD("vk_khr_get_memory_requirements2", "", CVAR_VIDEOLATCH, "Enable extended memory info querires");
static cvar_t vk_khr_dedicated_allocation = CVARFD("vk_khr_dedicated_allocation", "", CVAR_VIDEOLATCH, "Flag vulkan memory allocations as dedicated, where applicable.");
static cvar_t vk_khr_push_descriptor = CVARFD("vk_khr_push_descriptor", "", CVAR_VIDEOLATCH, "Enables better descriptor streaming.");
static cvar_t vk_amd_rasterization_order = CVARFD("vk_amd_rasterization_order", "", CVAR_VIDEOLATCH, "Enables the use of relaxed rasterization ordering, for a small speedup at the minor risk of a little zfighting.");
#ifdef VK_EXT_astc_decode_mode
static cvar_t vk_ext_astc_decode_mode = CVARFD("vk_ext_astc_decode_mode", "", CVAR_VIDEOLATCH, "Enables reducing texture cache sizes for LDR ASTC-compressed textures.");
#endif
extern cvar_t vid_srgb, vid_vsync, vid_triplebuffer, r_stereo_method, vid_multisample, vid_bpp;
void VK_RegisterVulkanCvars(void)
{
#define VKRENDEREROPTIONS "Vulkan-Specific Renderer Options"
Cvar_Register (&vk_stagingbuffers, VKRENDEREROPTIONS);
Cvar_Register (&vk_submissionthread, VKRENDEREROPTIONS);
Cvar_Register (&vk_debug, VKRENDEREROPTIONS);
Cvar_Register (&vk_dualqueue, VKRENDEREROPTIONS);
Cvar_Register (&vk_busywait, VKRENDEREROPTIONS);
Cvar_Register (&vk_waitfence, VKRENDEREROPTIONS);
Cvar_Register (&vk_usememorypools, VKRENDEREROPTIONS);
Cvar_Register (&vk_nv_glsl_shader, VKRENDEREROPTIONS);
Cvar_Register (&vk_khr_get_memory_requirements2,VKRENDEREROPTIONS);
Cvar_Register (&vk_khr_dedicated_allocation,VKRENDEREROPTIONS);
Cvar_Register (&vk_khr_push_descriptor, VKRENDEREROPTIONS);
Cvar_Register (&vk_amd_rasterization_order, VKRENDEREROPTIONS);
#ifdef VK_EXT_astc_decode_mode
Cvar_Register (&vk_ext_astc_decode_mode, VKRENDEREROPTIONS);
#endif
}
void R2D_Console_Resize(void);
extern qboolean scr_con_forcedraw;
@ -1299,7 +1326,10 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay
vk_image_t ret;
VkImageViewCreateInfo viewInfo = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
VkImageCreateInfo ici = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
VkFormat format = VK_FORMAT_UNDEFINED;;
VkFormat format = VK_FORMAT_UNDEFINED;
#ifdef VK_EXT_astc_decode_mode
VkImageViewASTCDecodeModeEXT astcmode;
#endif
ret.width = width;
ret.height = height;
@ -1370,34 +1400,65 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay
case PTI_EAC_RG11: format = VK_FORMAT_EAC_R11G11_UNORM_BLOCK; break;
case PTI_EAC_RG11_SNORM: format = VK_FORMAT_EAC_R11G11_SNORM_BLOCK; break;
case PTI_ASTC_4X4: format = VK_FORMAT_ASTC_4x4_UNORM_BLOCK; break;
case PTI_ASTC_4X4_LDR: format = VK_FORMAT_ASTC_4x4_UNORM_BLOCK; break;
case PTI_ASTC_4X4_SRGB: format = VK_FORMAT_ASTC_4x4_SRGB_BLOCK; break;
case PTI_ASTC_5X4: format = VK_FORMAT_ASTC_5x4_UNORM_BLOCK; break;
case PTI_ASTC_5X4_LDR: format = VK_FORMAT_ASTC_5x4_UNORM_BLOCK; break;
case PTI_ASTC_5X4_SRGB: format = VK_FORMAT_ASTC_5x4_SRGB_BLOCK; break;
case PTI_ASTC_5X5: format = VK_FORMAT_ASTC_5x5_UNORM_BLOCK; break;
case PTI_ASTC_5X5_LDR: format = VK_FORMAT_ASTC_5x5_UNORM_BLOCK; break;
case PTI_ASTC_5X5_SRGB: format = VK_FORMAT_ASTC_5x5_SRGB_BLOCK; break;
case PTI_ASTC_6X5: format = VK_FORMAT_ASTC_6x5_UNORM_BLOCK; break;
case PTI_ASTC_6X5_LDR: format = VK_FORMAT_ASTC_6x5_UNORM_BLOCK; break;
case PTI_ASTC_6X5_SRGB: format = VK_FORMAT_ASTC_6x5_SRGB_BLOCK; break;
case PTI_ASTC_6X6: format = VK_FORMAT_ASTC_6x6_UNORM_BLOCK; break;
case PTI_ASTC_6X6_LDR: format = VK_FORMAT_ASTC_6x6_UNORM_BLOCK; break;
case PTI_ASTC_6X6_SRGB: format = VK_FORMAT_ASTC_6x6_SRGB_BLOCK; break;
case PTI_ASTC_8X5: format = VK_FORMAT_ASTC_8x5_UNORM_BLOCK; break;
case PTI_ASTC_8X5_LDR: format = VK_FORMAT_ASTC_8x5_UNORM_BLOCK; break;
case PTI_ASTC_8X5_SRGB: format = VK_FORMAT_ASTC_8x5_SRGB_BLOCK; break;
case PTI_ASTC_8X6: format = VK_FORMAT_ASTC_8x6_UNORM_BLOCK; break;
case PTI_ASTC_8X6_LDR: format = VK_FORMAT_ASTC_8x6_UNORM_BLOCK; break;
case PTI_ASTC_8X6_SRGB: format = VK_FORMAT_ASTC_8x6_SRGB_BLOCK; break;
case PTI_ASTC_8X8: format = VK_FORMAT_ASTC_8x8_UNORM_BLOCK; break;
case PTI_ASTC_8X8_LDR: format = VK_FORMAT_ASTC_8x8_UNORM_BLOCK; break;
case PTI_ASTC_8X8_SRGB: format = VK_FORMAT_ASTC_8x8_SRGB_BLOCK; break;
case PTI_ASTC_10X5: format = VK_FORMAT_ASTC_10x5_UNORM_BLOCK; break;
case PTI_ASTC_10X5_LDR: format = VK_FORMAT_ASTC_10x5_UNORM_BLOCK; break;
case PTI_ASTC_10X5_SRGB: format = VK_FORMAT_ASTC_10x5_SRGB_BLOCK; break;
case PTI_ASTC_10X6: format = VK_FORMAT_ASTC_10x6_UNORM_BLOCK; break;
case PTI_ASTC_10X6_LDR: format = VK_FORMAT_ASTC_10x6_UNORM_BLOCK; break;
case PTI_ASTC_10X6_SRGB: format = VK_FORMAT_ASTC_10x6_SRGB_BLOCK; break;
case PTI_ASTC_10X8: format = VK_FORMAT_ASTC_10x8_UNORM_BLOCK; break;
case PTI_ASTC_10X8_LDR: format = VK_FORMAT_ASTC_10x8_UNORM_BLOCK; break;
case PTI_ASTC_10X8_SRGB: format = VK_FORMAT_ASTC_10x8_SRGB_BLOCK; break;
case PTI_ASTC_10X10: format = VK_FORMAT_ASTC_10x10_UNORM_BLOCK; break;
case PTI_ASTC_10X10_LDR: format = VK_FORMAT_ASTC_10x10_UNORM_BLOCK; break;
case PTI_ASTC_10X10_SRGB: format = VK_FORMAT_ASTC_10x10_SRGB_BLOCK; break;
case PTI_ASTC_12X10: format = VK_FORMAT_ASTC_12x10_UNORM_BLOCK; break;
case PTI_ASTC_12X10_LDR: format = VK_FORMAT_ASTC_12x10_UNORM_BLOCK; break;
case PTI_ASTC_12X10_SRGB: format = VK_FORMAT_ASTC_12x10_SRGB_BLOCK; break;
case PTI_ASTC_12X12: format = VK_FORMAT_ASTC_12x12_UNORM_BLOCK; break;
case PTI_ASTC_12X12_LDR: format = VK_FORMAT_ASTC_12x12_UNORM_BLOCK; break;
case PTI_ASTC_12X12_SRGB: format = VK_FORMAT_ASTC_12x12_SRGB_BLOCK; break;
#ifdef VK_EXT_texture_compression_astc_hdr
case PTI_ASTC_4X4_HDR: format = VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT; break;
case PTI_ASTC_5X4_HDR: format = VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT; break;
case PTI_ASTC_5X5_HDR: format = VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT; break;
case PTI_ASTC_6X5_HDR: format = VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT; break;
case PTI_ASTC_6X6_HDR: format = VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT; break;
case PTI_ASTC_8X5_HDR: format = VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT; break;
case PTI_ASTC_8X6_HDR: format = VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT; break;
case PTI_ASTC_8X8_HDR: format = VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT; break;
case PTI_ASTC_10X5_HDR: format = VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT; break;
case PTI_ASTC_10X6_HDR: format = VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT; break;
case PTI_ASTC_10X8_HDR: format = VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT; break;
case PTI_ASTC_10X10_HDR: format = VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT; break;
case PTI_ASTC_12X10_HDR: format = VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT; break;
case PTI_ASTC_12X12_HDR: format = VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT; break;
#else //better than crashing.
case PTI_ASTC_4X4_HDR: format = VK_FORMAT_ASTC_4x4_UNORM_BLOCK; break;
case PTI_ASTC_5X4_HDR: format = VK_FORMAT_ASTC_5x4_UNORM_BLOCK; break;
case PTI_ASTC_5X5_HDR: format = VK_FORMAT_ASTC_5x5_UNORM_BLOCK; break;
case PTI_ASTC_6X5_HDR: format = VK_FORMAT_ASTC_6x5_UNORM_BLOCK; break;
case PTI_ASTC_6X6_HDR: format = VK_FORMAT_ASTC_6x6_UNORM_BLOCK; break;
case PTI_ASTC_8X5_HDR: format = VK_FORMAT_ASTC_8x5_UNORM_BLOCK; break;
case PTI_ASTC_8X6_HDR: format = VK_FORMAT_ASTC_8x6_UNORM_BLOCK; break;
case PTI_ASTC_8X8_HDR: format = VK_FORMAT_ASTC_8x8_UNORM_BLOCK; break;
case PTI_ASTC_10X5_HDR: format = VK_FORMAT_ASTC_10x5_UNORM_BLOCK; break;
case PTI_ASTC_10X6_HDR: format = VK_FORMAT_ASTC_10x6_UNORM_BLOCK; break;
case PTI_ASTC_10X8_HDR: format = VK_FORMAT_ASTC_10x8_UNORM_BLOCK; break;
case PTI_ASTC_10X10_HDR: format = VK_FORMAT_ASTC_10x10_UNORM_BLOCK; break;
case PTI_ASTC_12X10_HDR: format = VK_FORMAT_ASTC_12x10_UNORM_BLOCK; break;
case PTI_ASTC_12X12_HDR: format = VK_FORMAT_ASTC_12x12_UNORM_BLOCK; break;
#endif
//depth formats
case PTI_DEPTH16: format = VK_FORMAT_D16_UNORM; break;
@ -1473,7 +1534,8 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay
viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
viewInfo.components.a = VK_COMPONENT_SWIZZLE_ONE;
break;
case PTI_L8: //must be an R8 texture
case PTI_L8: //must be an R8 texture
case PTI_L8_SRGB: //must be an R8 texture
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_R;
@ -1491,6 +1553,35 @@ vk_image_t VK_CreateTexture2DArray(uint32_t width, uint32_t height, uint32_t lay
viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
break;
#ifdef VK_EXT_astc_decode_mode
case PTI_ASTC_4X4: //set these to use rgba8 decoding, because we know they're not hdr and the format is basically 8bit anyway.
case PTI_ASTC_5X4: //we do NOT do this for the hdr, as that would cause data loss.
case PTI_ASTC_5X5: //we do NOT do this for sRGB because its pointless.
case PTI_ASTC_6X5:
case PTI_ASTC_6X6:
case PTI_ASTC_8X5:
case PTI_ASTC_8X6:
case PTI_ASTC_8X8:
case PTI_ASTC_10X5:
case PTI_ASTC_10X6:
case PTI_ASTC_10X8:
case PTI_ASTC_10X10:
case PTI_ASTC_12X10:
case PTI_ASTC_12X12:
viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
if (vk.ext_astc_decode_mode)
{
astcmode.pNext = viewInfo.pNext;
astcmode.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT;
astcmode.decodeMode = VK_FORMAT_R8G8B8A8_UNORM;
viewInfo.pNext = &astcmode;
}
break;
#endif
}
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
@ -3994,7 +4085,9 @@ void VK_CheckTextureFormats(void)
{PTI_ARGB1555, VK_FORMAT_A1R5G5B5_UNORM_PACK16, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_RGBA16F, VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT},
{PTI_RGBA32F, VK_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT},
{PTI_P8, VK_FORMAT_R8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT},
{PTI_L8, VK_FORMAT_R8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT},
{PTI_L8A8, VK_FORMAT_R8G8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT},
{PTI_L8_SRGB, VK_FORMAT_R8_SRGB, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT},
{PTI_R8, VK_FORMAT_R8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT},
{PTI_RG8, VK_FORMAT_R8G8_UNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT},
{PTI_R8_SNORM, VK_FORMAT_R8_SNORM, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT},
@ -4036,34 +4129,51 @@ void VK_CheckTextureFormats(void)
{PTI_EAC_R11_SNORM, VK_FORMAT_EAC_R11_SNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_EAC_RG11, VK_FORMAT_EAC_R11G11_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_EAC_RG11_SNORM, VK_FORMAT_EAC_R11G11_SNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_4X4, VK_FORMAT_ASTC_4x4_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_4X4_LDR, VK_FORMAT_ASTC_4x4_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_5X4_LDR, VK_FORMAT_ASTC_5x4_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_5X5_LDR, VK_FORMAT_ASTC_5x5_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_6X5_LDR, VK_FORMAT_ASTC_6x5_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_6X6_LDR, VK_FORMAT_ASTC_6x6_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_8X5_LDR, VK_FORMAT_ASTC_8x5_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_8X6_LDR, VK_FORMAT_ASTC_8x6_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_8X8_LDR, VK_FORMAT_ASTC_8x8_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_10X5_LDR, VK_FORMAT_ASTC_10x5_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_10X6_LDR, VK_FORMAT_ASTC_10x6_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_10X8_LDR, VK_FORMAT_ASTC_10x8_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_10X10_LDR, VK_FORMAT_ASTC_10x10_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_12X10_LDR, VK_FORMAT_ASTC_12x10_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_12X12_LDR, VK_FORMAT_ASTC_12x12_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_4X4_SRGB, VK_FORMAT_ASTC_4x4_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_5X4, VK_FORMAT_ASTC_5x4_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_5X4_SRGB, VK_FORMAT_ASTC_5x4_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_5X5, VK_FORMAT_ASTC_5x5_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_5X5_SRGB, VK_FORMAT_ASTC_5x5_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_6X5, VK_FORMAT_ASTC_6x5_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_6X5_SRGB, VK_FORMAT_ASTC_6x5_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_6X6, VK_FORMAT_ASTC_6x6_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_6X6_SRGB, VK_FORMAT_ASTC_6x6_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_8X5, VK_FORMAT_ASTC_8x5_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_8X5_SRGB, VK_FORMAT_ASTC_8x5_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_8X6, VK_FORMAT_ASTC_8x6_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_8X6_SRGB, VK_FORMAT_ASTC_8x6_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_8X8, VK_FORMAT_ASTC_8x8_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_8X8_SRGB, VK_FORMAT_ASTC_8x8_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_10X5, VK_FORMAT_ASTC_10x5_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_10X5_SRGB, VK_FORMAT_ASTC_10x5_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_10X6, VK_FORMAT_ASTC_10x6_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_10X6_SRGB, VK_FORMAT_ASTC_10x6_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_10X8, VK_FORMAT_ASTC_10x8_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_10X8_SRGB, VK_FORMAT_ASTC_10x8_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_10X10, VK_FORMAT_ASTC_10x10_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_10X10_SRGB, VK_FORMAT_ASTC_10x10_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_12X10, VK_FORMAT_ASTC_12x10_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_12X10_SRGB, VK_FORMAT_ASTC_12x10_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_12X12, VK_FORMAT_ASTC_12x12_UNORM_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_12X12_SRGB, VK_FORMAT_ASTC_12x12_SRGB_BLOCK, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
#ifdef VK_EXT_texture_compression_astc_hdr
{PTI_ASTC_4X4_HDR, VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_5X4_HDR, VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_5X5_HDR, VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_6X5_HDR, VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_6X6_HDR, VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_8X5_HDR, VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_8X6_HDR, VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_8X8_HDR, VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_10X5_HDR, VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_10X6_HDR, VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_10X8_HDR, VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_10X10_HDR, VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_12X10_HDR, VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
{PTI_ASTC_12X12_HDR, VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT},
#endif
};
unsigned int i;
VkPhysicalDeviceProperties props;
@ -4083,6 +4193,15 @@ void VK_CheckTextureFormats(void)
if ((fmt.optimalTilingFeatures & need) == need)
sh_config.texfmt[texfmt[i].pti] = true;
}
if (sh_config.texfmt[PTI_BC1_RGBA] && sh_config.texfmt[PTI_BC2_RGBA] && sh_config.texfmt[PTI_BC3_RGBA] && sh_config.texfmt[PTI_BC5_RG8] && sh_config.texfmt[PTI_BC7_RGBA])
sh_config.hw_bc = 3;
if (sh_config.texfmt[PTI_ETC2_RGB8] && sh_config.texfmt[PTI_ETC2_RGB8A1] && sh_config.texfmt[PTI_ETC2_RGB8A8] && sh_config.texfmt[PTI_EAC_RG11])
sh_config.hw_etc = 2;
if (sh_config.texfmt[PTI_ASTC_4X4_LDR])
sh_config.hw_astc = 1; //the core vulkan formats refer to the ldr profile. hdr is a separate extension, which is still not properly specified..
if (sh_config.texfmt[PTI_ASTC_4X4_HDR])
sh_config.hw_astc = 2; //the core vulkan formats refer to the ldr profile. hdr is a separate extension, which is still not properly specified..
}
//initialise the vulkan instance, context, device, etc.
@ -4115,6 +4234,9 @@ qboolean VK_Init(rendererstate_t *info, const char **sysextnames, qboolean (*cre
{&vk.khr_dedicated_allocation, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, &vk_khr_dedicated_allocation, true, NULL, NULL},
{&vk.khr_push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, &vk_khr_push_descriptor, true, NULL, NULL},
{&vk.amd_rasterization_order, VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME, &vk_amd_rasterization_order, false, NULL, NULL},
#ifdef VK_EXT_astc_decode_mode
{&vk.ext_astc_decode_mode, VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME, &vk_ext_astc_decode_mode, true, NULL, NULL},
#endif
};
size_t e;

View File

@ -280,6 +280,7 @@ extern struct vulkaninfo_s
qboolean khr_dedicated_allocation; //standardised version of the above where the driver decides whether a resource is worth a dedicated allocation.
qboolean khr_push_descriptor; //more efficient descriptor streaming
qboolean amd_rasterization_order; //allows primitives to draw in any order
qboolean ext_astc_decode_mode; //small perf boost
VkInstance instance;
VkDevice device;

660
plugins/models/exportiqm.c Normal file
View File

@ -0,0 +1,660 @@
#ifndef GLQUAKE
#define GLQUAKE //this is shit.
#endif
#include "quakedef.h"
#include "../plugin.h"
#include "com_mesh.h"
extern plugmodfuncs_t *modfuncs;
extern plugfsfuncs_t *filefuncs;
#define IQM_MAGIC "INTERQUAKEMODEL"
#define IQM_VERSION2 2
struct iqmheader
{
char magic[16];
unsigned int version;
unsigned int filesize;
unsigned int flags;
unsigned int num_text, ofs_text;
unsigned int num_meshes, ofs_meshes;
unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
unsigned int num_triangles, ofs_triangles, ofs_adjacency;
unsigned int num_joints, ofs_joints;
unsigned int num_poses, ofs_poses;
unsigned int num_anims, ofs_anims;
unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
unsigned int num_comment, ofs_comment;
unsigned int num_extensions, ofs_extensions;
};
struct iqmmesh
{
unsigned int name;
unsigned int material;
unsigned int first_vertex, num_vertexes;
unsigned int first_triangle, num_triangles;
};
enum
{
IQM_POSITION = 0,
IQM_TEXCOORD = 1,
IQM_NORMAL = 2,
IQM_TANGENT = 3,
IQM_BLENDINDEXES = 4,
IQM_BLENDWEIGHTS = 5,
IQM_COLOR = 6,
IQM_CUSTOM = 0x10
};
enum
{
IQM_BYTE = 0,
IQM_UBYTE = 1,
IQM_SHORT = 2,
IQM_USHORT = 3,
IQM_INT = 4,
IQM_UINT = 5,
IQM_HALF = 6,
IQM_FLOAT = 7,
IQM_DOUBLE = 8,
};
struct iqmtriangle
{
unsigned int vertex[3];
};
struct iqmjoint2
{
unsigned int name;
int parent;
float translate[3], rotate[4], scale[3];
};
struct iqmpose2
{
int parent;
unsigned int mask;
float channeloffset[10];
float channelscale[10];
};
struct iqmanim
{
unsigned int name;
unsigned int first_frame, num_frames;
float framerate;
unsigned int flags;
};
enum
{
IQM_LOOP = 1<<0
};
struct iqmvertexarray
{
unsigned int type;
unsigned int flags;
unsigned int format;
unsigned int size;
unsigned int offset;
};
struct iqmbounds
{
float bbmin[3], bbmax[3];
float xyradius, radius;
};
struct iqmextension
{
unsigned int name;
unsigned int num_data, ofs_data;
unsigned int ofs_extensions; // pointer to next extension. wtf is up with this? how is this not redundant due to ofs_data?
};
struct iqmext_fte_mesh
{
unsigned int contents; //default CONTENTS_BODY
unsigned int surfaceflags; //propagates to trace_surfaceflags
unsigned int surfaceid; //the body reported to qc via trace_surface
unsigned int geomset;
unsigned int geomid;
float mindist;
float maxdist;
};
struct iqmext_fte_event
{
unsigned int anim;
float timestamp;
unsigned int evcode;
unsigned int evdata_str; //stringtable
};
static void CrossProduct_ (const vec3_t v1, const vec3_t v2, vec3_t cross)
{
cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
}
static void Bone_To_PosQuat4(const float *matrix, float *pos, float *quat4, float *scale)
{ //I originally ripped this function out of DP. tweaked slightly.
//http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
float origininvscale = 1;
float origin[3];
float quat[4];
float quatscale;
float trace = matrix[0*4+0] + matrix[1*4+1] + matrix[2*4+2];
origin[0] = matrix[0*4+0];
origin[1] = matrix[1*4+0];
origin[2] = matrix[2*4+0];
scale [0] = sqrt(DotProduct(origin,origin));
origin[0] = matrix[0*4+1];
origin[1] = matrix[1*4+1];
origin[2] = matrix[2*4+1];
scale [1] = sqrt(DotProduct(origin,origin));
origin[1] = matrix[0*4+2];
origin[1] = matrix[1*4+2];
origin[2] = matrix[2*4+2];
scale [2] = sqrt(DotProduct(origin,origin));
origin[0] = matrix[0*4+3];
origin[1] = matrix[1*4+3];
origin[2] = matrix[2*4+3];
if(trace > 0)
{
float r = sqrt(1.0f + trace), inv = 0.5f / r;
quat[0] = (matrix[2*4+1] - matrix[1*4+2]) * inv;
quat[1] = (matrix[0*4+2] - matrix[2*4+0]) * inv;
quat[2] = (matrix[1*4+0] - matrix[0*4+1]) * inv;
quat[3] = 0.5f * r;
}
else if(matrix[0*4+0] > matrix[1*4+1] && matrix[0*4+0] > matrix[2*4+2])
{
float r = sqrt(1.0f + matrix[0*4+0] - matrix[1*4+1] - matrix[2*4+2]), inv = 0.5f / r;
quat[0] = 0.5f * r;
quat[1] = (matrix[1*4+0] + matrix[0*4+1]) * inv;
quat[2] = (matrix[0*4+2] + matrix[2*4+0]) * inv;
quat[3] = (matrix[2*4+1] - matrix[1*4+2]) * inv;
}
else if(matrix[1*4+1] > matrix[2*4+2])
{
float r = sqrt(1.0f + matrix[1*4+1] - matrix[0*4+0] - matrix[2*4+2]), inv = 0.5f / r;
quat[0] = (matrix[1*4+0] + matrix[0*4+1]) * inv;
quat[1] = 0.5f * r;
quat[2] = (matrix[2*4+1] + matrix[1*4+2]) * inv;
quat[3] = (matrix[0*4+2] - matrix[2*4+0]) * inv;
}
else
{
float r = sqrt(1.0f + matrix[2*4+2] - matrix[0*4+0] - matrix[1*4+1]), inv = 0.5f / r;
quat[0] = (matrix[0*4+2] + matrix[2*4+0]) * inv;
quat[1] = (matrix[2*4+1] + matrix[1*4+2]) * inv;
quat[2] = 0.5f * r;
quat[3] = (matrix[1*4+0] - matrix[0*4+1]) * inv;
}
// normalize quaternion so that it is unit length
quatscale = quat[0]*quat[0]+quat[1]*quat[1]+quat[2]*quat[2]+quat[3]*quat[3];
if (quatscale)
quatscale = (quat[3] >= 0 ? -1.0f : 1.0f) / sqrt(quatscale);
// use a negative scale on the quat because the above function produces a
// positive quat[3] and canonical quaternions have negative quat[3]
VectorScale(origin, origininvscale, pos);
Vector4Scale(quat, quatscale, quat4);
}
void Mod_ExportIQM(char *fname, int flags, galiasinfo_t *mesh)
{
int i, j, k;
vfsfile_t *f;
galiasinfo_t *m;
qbyte *data = NULL;
char *otext;
struct iqmvertexarray *ovarr;
struct iqmtriangle *otri;
struct iqmmesh *omesh;
struct iqmjoint2 *ojoint;
struct iqmanim *oanim;
struct iqmpose2 *opose;
struct
{
float min[10], max[10], scale[10];
int flags;
} *poseinfo = NULL, *pi; //per bone
struct
{ //pos3, quat4, scale3
float posquatscale[10]; //raw values, used to calibrate ranges
} *posedata = NULL, *pd; //per bone*joint
avec4_t *ivert;
vec2_t *ist;
vec3_t *overt;
vec3_t *onorm = NULL;
vec4_t *otang = NULL;
vec2_t *ost;
bone_vec4_t *oboneidx;
byte_vec4_t *oboneweight;
unsigned short *oposedata;
struct iqmheader hdr = {IQM_MAGIC, IQM_VERSION2}, *oh;
hdr.flags = flags;
hdr.num_vertexarrays = 4;
hdr.num_triangles = 0;
hdr.ofs_adjacency = 0; //noone actually uses this...
hdr.num_poses = 0;
// hdr.ofs_poses = 0;
hdr.num_anims = 0;
// hdr.ofs_anims = 0;
hdr.num_frames = 0;
hdr.num_framechannels = 0;
// hdr.ofs_frames = 0;
// hdr.ofs_bounds = 0;
hdr.num_comment = 0;
// hdr.ofs_comment = 0;
hdr.num_extensions = 0;
// hdr.ofs_extensions = 0;
hdr.num_joints = mesh->numbones;
if (hdr.num_joints)
{
float *matrix;
hdr.num_vertexarrays+= 2;
hdr.num_anims = mesh->numanimations;
for (i = 0; i < hdr.num_anims; i++)
{
hdr.num_text += strlen(mesh->ofsanimations[i].name)+1;
hdr.num_frames += mesh->ofsanimations[i].numposes;
}
if (hdr.num_frames)
{
poseinfo = malloc(sizeof(*poseinfo)*hdr.num_joints);
hdr.num_poses = hdr.num_joints;
posedata = malloc(sizeof(*posedata)*hdr.num_joints*hdr.num_poses);
//pull out the raw data and convert to the quats that we need
for (i = 0, pd = posedata; i < hdr.num_anims; i++)
for (j = 0, matrix = mesh->ofsanimations[i].boneofs; j < mesh->ofsanimations[i].numposes; j++)
for (k = 0; k < hdr.num_joints; k++)
{
Bone_To_PosQuat4(matrix, &pd->posquatscale[0], &pd->posquatscale[3], &pd->posquatscale[7]);
pd++;
matrix+=12;
}
//now figure out each poseinfo's min+max
for (i = 0, pi = poseinfo; i < hdr.num_joints; i++, pi++)
for (j = 0, pd = posedata+i; j < hdr.num_poses; j++, pd+=hdr.num_joints)
for (k = 0; k < 10; k++)
{
if (!i || pd->posquatscale[k] < pi->min[k])
pi->min[k] = pd->posquatscale[k];
if (!i || pi[i].max[k] < pd->posquatscale[k])
pi->max[k] = pd->posquatscale[k];
}
//figure out the offset+range+flags
for (i = 0, pi = poseinfo; i < hdr.num_joints; i++, pi++)
for (k = 0; k < 10; k++)
{
pi->scale[k] = pi->max[k]-pi->min[k];
if (pi->scale[k] < 1e-10f)
; //total range is tiny and won't make any real difference, drop this channel for a small saving.
else
{
pi->scale[k] /= 0xffffu; //compensate for the datatype's max
pi->flags |= 1u<<k;
hdr.num_framechannels++;
}
}
hdr.num_framechannels *= hdr.num_frames; //there'll be one for each pose*channel*frame
}
}
hdr.num_text += hdr.num_joints*32; //gah
//count needed data
for (m = mesh; m; m = m->nextsurf)
{
//can't handle the surface if its verts are weird.
if (m->shares_verts && m->shares_verts != hdr.num_meshes)
continue;
//can only handle one set of bones.
if (m->shares_bones != 0)
continue;
//and must have the same number of bones.
if (hdr.num_joints != m->numbones)
continue;
hdr.num_text += strlen(m->surfacename)+1;
if (m->ofsskins && m->ofsskins->frame)
hdr.num_text += strlen(m->ofsskins->frame->shadername)+1;
hdr.num_triangles += m->numindexes/3;
hdr.num_vertexes += m->numverts;
hdr.num_meshes++;
}
//allocate our output buffer
#define ALLOCSPACE hdr.filesize = 0; \
ALLOC(oh, sizeof(*oh)); \
ALLOC(otext, sizeof(*otext)*hdr.num_text); \
ALLOC(ovarr, sizeof(*ovarr)*hdr.num_vertexarrays); \
ALLOC(otri, sizeof(*otri)*hdr.num_triangles); \
ALLOC(overt, sizeof(*overt)*hdr.num_vertexes); \
ALLOC(ost, sizeof(*ost)*hdr.num_vertexes); \
if (mesh->ofs_skel_norm) {ALLOC(onorm, sizeof(*onorm)*hdr.num_vertexes);} \
if (mesh->ofs_skel_svect && mesh->ofs_skel_tvect) {ALLOC(otang, sizeof(*otang)*hdr.num_vertexes);} \
if (hdr.num_joints) {ALLOC(oboneweight, sizeof(*oboneweight)*hdr.num_vertexes);} \
if (hdr.num_joints) {ALLOC(oboneidx, sizeof(*oboneidx)*hdr.num_vertexes);} \
if (hdr.num_joints) {ALLOC(ojoint, sizeof(*ojoint)*hdr.num_joints);} \
if (hdr.num_anims) {ALLOC(oanim, sizeof(*oanim)*hdr.num_anims);} \
if (hdr.num_poses) {ALLOC(opose, sizeof(*opose)*hdr.num_poses);} \
if (hdr.num_framechannels) {ALLOC(oposedata, sizeof(*oposedata)*hdr.num_framechannels);} \
ALLOC(omesh, sizeof(*omesh)*hdr.num_meshes);
#define ALLOC(p,s) p=(void*)(data+hdr.filesize);hdr.filesize+=s;
ALLOCSPACE; //figure out how much space we need
data = malloc(hdr.filesize);
memset(data, 0xFE, hdr.filesize);
ALLOCSPACE; //and assign everything to the right offsets.
#undef ALLOC
#undef ALLOCSPACE
//copy over the preliminary header
*oh = hdr;
#define hdr hdr
if (omesh) oh->ofs_meshes = (qbyte*)omesh-data;
if (otext) oh->ofs_text = (qbyte*)otext-data;
if (ovarr) oh->ofs_vertexarrays = (qbyte*)ovarr-data;
if (otri) oh->ofs_triangles = (qbyte*)otri-data;
if (ojoint) oh->ofs_joints = (qbyte*)ojoint-data;
if (opose) oh->ofs_poses = (qbyte*)opose-data;
if (oposedata) oh->ofs_frames = (qbyte*)oposedata-data;
if (oanim) oh->ofs_anims = (qbyte*)oanim-data;
//set up vertex array data. we might add some padding here, in case the extra data isn't availble.
memset(ovarr, 0, sizeof(*ovarr)*oh->num_vertexarrays);
oh->num_vertexarrays=0;
ovarr->type = IQM_POSITION;
ovarr->flags = 0;
ovarr->format = IQM_FLOAT;
ovarr->size = 3;
ovarr->offset = (qbyte*)overt - data;
ovarr++;
oh->num_vertexarrays++;
ovarr->type = IQM_TEXCOORD;
ovarr->flags = 0;
ovarr->format = IQM_FLOAT;
ovarr->size = 2;
ovarr->offset = (qbyte*)ost - data;
ovarr++;
oh->num_vertexarrays++;
if (onorm)
{
ovarr->type = IQM_NORMAL;
ovarr->flags = 0;
ovarr->format = IQM_FLOAT;
ovarr->size = 3;
ovarr->offset = (qbyte*)onorm - data;
ovarr++;
oh->num_vertexarrays++;
}
if (otang)
{
ovarr->type = IQM_TANGENT;
ovarr->flags = 0;
ovarr->format = IQM_FLOAT;
ovarr->size = 4;
ovarr->offset = (qbyte*)otang - data;
ovarr++;
oh->num_vertexarrays++;
}
if (oboneidx)
{
ovarr->type = IQM_BLENDINDEXES;
ovarr->flags = 0;
ovarr->format = (MAX_BONES>65536)?IQM_UINT:((MAX_BONES>256)?IQM_USHORT:IQM_UBYTE);
ovarr->size = 4;
ovarr->offset = (qbyte*)oboneidx - data;
ovarr++;
oh->num_vertexarrays++;
}
if (oboneweight)
{
ovarr->type = IQM_BLENDWEIGHTS;
ovarr->flags = 0;
ovarr->format = IQM_BYTE;
ovarr->size = 4;
ovarr->offset = (qbyte*)oboneweight - data;
ovarr++;
oh->num_vertexarrays++;
}
/*if (orgba)
{
ovarr->type = IQM_COLOR;
ovarr->flags = 0;
ovarr->format = IQM_FLOAT;
ovarr->size = 4;
ovarr->offset = (qbyte*)orgba - data;
ovarr++;
oh->num_vertexarrays++;
}*/
if (ojoint)
{
for (i = 0; i < hdr.num_joints; i++)
{
ojoint[i].parent = mesh->ofsbones[i].parent;
ojoint[i].name = (qbyte*)otext-(data+oh->ofs_text);
strcpy(otext, mesh->ofsbones[i].name);
otext += strlen(otext)+1;
Bone_To_PosQuat4(mesh->ofsbones[i].inverse, ojoint[i].translate, ojoint[i].rotate, ojoint[i].scale);
}
}
if (opose)
{
int c;
for (i = 0, pi=poseinfo; i < hdr.num_joints; i++, pi++)
{
opose[i].parent = mesh->ofsbones[i].parent;
opose[i].mask = pi->flags;
for (k = 0; k < 10; k++)
{
opose[i].channeloffset[k] = pi->min[k];
opose[i].channelscale[k] = pi->scale[k];
}
for (j = 0, pd = posedata+i; j < hdr.num_frames; j++, pd+=hdr.num_joints)
{
for (k = 0; k < 10; k++)
{
if (opose[i].mask & (1<<k))
{
c = (pd->posquatscale[k]-pi->min[k])/pi->scale[k];
c = bound(0, c, 0xffff); //clamp it just in case (floats can be annoying)
*oposedata++ = c;
}
}
}
}
}
if (oposedata)
{
for (i = 0; i < hdr.num_joints; i++)
{
opose[i].parent = mesh->ofsbones[i].parent;
opose[i].mask = poseinfo[i].flags;
for (k = 0; k < 10; k++)
{
opose[i].channeloffset[k] = poseinfo[i].min[k];
opose[i].channelscale[k] = poseinfo[i].scale[k];
}
}
}
hdr.num_frames = 0;
for (i = 0; i < hdr.num_anims; i++, oanim++)
{
oanim->first_frame = hdr.num_frames;
oanim->num_frames = mesh->ofsanimations[i].numposes;
oanim->framerate = mesh->ofsanimations[i].rate;
oanim->flags = mesh->ofsanimations[i].loop?IQM_LOOP:0;
oanim->name = (qbyte*)otext-(data+oh->ofs_text);
strcpy(otext, mesh->ofsanimations[i].name);
otext += strlen(otext)+1;
hdr.num_frames += mesh->ofsanimations[i].numposes;
}
oh->num_anims = i;
oh->num_frames = hdr.num_frames;
//count needed data
hdr.num_triangles = 0;
hdr.num_vertexes = 0;
for (m = mesh; m; m = m->nextsurf)
{
//can't handle the surface if its verts are weird.
if (m->shares_verts && m->shares_verts != hdr.num_meshes)
continue;
//can only handle one set of bones.
if (m->shares_bones != 0)
continue;
if (hdr.num_joints != m->numbones)
continue;
omesh->name = (qbyte*)otext-(data+oh->ofs_text);
strcpy(otext, m->surfacename);
otext += strlen(otext)+1;
omesh->material = (qbyte*)otext-(data+oh->ofs_text);
if (m->ofsskins && m->ofsskins->frame)
strcpy(otext, m->ofsskins->frame->shadername);
else
strcpy(otext, "");
otext += strlen(otext)+1;
omesh->first_vertex = hdr.num_vertexes;
omesh->num_vertexes = m->numverts;
omesh->first_triangle = hdr.num_triangles;
omesh->num_triangles = m->numindexes/3;
if (m->ofs_skel_xyz)
ivert = m->ofs_skel_xyz;
else if (m->numanimations && m->ofsanimations->numposes)
ivert = m->ofsanimations->poseofs->ofsverts;
else
ivert = NULL;
if (ivert)
{
for (i = 0; i < omesh->num_vertexes; i++)
VectorCopy (ivert[i], overt[i]);
}
else
{
for (i = 0; i < omesh->num_vertexes; i++)
VectorClear (overt[i]);
}
overt += i;
if (oboneidx)
{
bone_vec4_t *iidx = m->ofs_skel_idx;
vec4_t *iweight = m->ofs_skel_weight;
for (i = 0; i < omesh->num_vertexes; i++)
{
Vector4Copy(iidx[i], oboneidx[i]);
Vector4Scale(iweight[i], 255, oboneweight[i]);
}
oboneidx += i;
oboneweight += i;
}
if (ost)
{
ist = m->ofs_st_array;
for (i = 0; i < omesh->num_vertexes; i++)
Vector2Copy(ist[i], ost[i]);
ost += i;
}
if (onorm)
{
vec3_t *inorm, *isdir, *itdir, t;
if (m->ofs_skel_norm)
{
inorm = m->ofs_skel_norm;
isdir = m->ofs_skel_svect;
itdir = m->ofs_skel_tvect;
}
else if (m->numanimations && m->ofsanimations->numposes)
{
inorm = m->ofsanimations->poseofs->ofsnormals;
isdir = m->ofsanimations->poseofs->ofssvector;
itdir = m->ofsanimations->poseofs->ofstvector;
}
else
{
inorm = NULL;
isdir = NULL;
itdir = NULL;
}
if (otang)
{
if (inorm && isdir && itdir)
{
for (i = 0; i < omesh->num_vertexes; i++)
{
VectorCopy (isdir[i], otang[i]);
CrossProduct_(isdir[i], inorm[i], t);
otang[i][3] = DotProduct(itdir[i], t)<0; //fourth part is simply a flag that says which direction the bitangent is in, should otherwise be a nice crossproduct result.
}
}
else
{
for (i = 0; i < omesh->num_vertexes; i++)
{
VectorClear (otang[i]);
otang[i][3] = 0;
}
}
otang += i;
}
if (inorm)
{
for (i = 0; i < omesh->num_vertexes; i++)
VectorCopy (ivert[i], onorm[i]);
}
else
{
for (i = 0; i < omesh->num_vertexes; i++)
VectorClear (onorm[i]);
}
otang += i;
onorm += i;
}
for (i = 0; i < omesh->num_triangles; i++)
{
otri[i].vertex[0] = m->ofs_indexes[i*3+0]+hdr.num_vertexes;
otri[i].vertex[1] = m->ofs_indexes[i*3+1]+hdr.num_vertexes;
otri[i].vertex[2] = m->ofs_indexes[i*3+2]+hdr.num_vertexes;
}
otri += i;
hdr.num_vertexes += omesh->num_vertexes;
hdr.num_triangles += omesh->num_triangles;
}
//and write it out
f = filefuncs->OpenVFS(fname, "wb", FS_GAMEONLY);
if (f)
{
VFS_WRITE(f, oh, oh->filesize);
VFS_CLOSE(f);
}
free(data);
free(poseinfo);
#undef hdr
}