From 3061ed448f19f5dfefa0849906f9bdea42639d2f Mon Sep 17 00:00:00 2001 From: Spoike Date: Sat, 11 Feb 2017 16:14:06 +0000 Subject: [PATCH] fix a silly performance-sapping typo. implemented identify+iplog stuff for nq users. r_tessellation forces blinn tessellation on meshes. can also be specified manually. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5055 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/botlib/q_platform.h | 2 + engine/client/cl_ignore.c | 8 +- engine/client/cl_ignore.h | 6 + engine/client/cl_main.c | 1 + engine/client/cl_screen.c | 2 +- engine/client/net_master.c | 6 +- engine/client/renderer.c | 8 +- engine/common/common.h | 1 + engine/common/gl_q2bsp.c | 11 + engine/common/log.c | 260 +++++++++++-- engine/common/net.h | 2 +- engine/common/net_wins.c | 135 +++++-- engine/dotnet2005/ftequake.vcproj | 21 +- engine/gl/gl_backend.c | 6 +- engine/gl/gl_model.c | 2 +- engine/gl/gl_rmain.c | 6 +- engine/gl/gl_shader.c | 57 ++- engine/gl/gl_vidcommon.c | 255 +++++++------ engine/gl/r_bishaders.h | 532 +++++++++++++++++++++++---- engine/gl/shader.h | 3 +- engine/server/server.h | 1 + engine/server/sv_ccmds.c | 4 +- engine/server/sv_main.c | 15 +- engine/server/sv_user.c | 2 +- engine/shaders/glsl/defaultskin.glsl | 144 +++++++- engine/shaders/glsl/defaultwall.glsl | 187 ++++++++-- engine/shaders/glsl/depthonly.glsl | 73 ++++ engine/shaders/glsl/rtlight.glsl | 178 ++++++--- 28 files changed, 1544 insertions(+), 384 deletions(-) diff --git a/engine/botlib/q_platform.h b/engine/botlib/q_platform.h index fd386202..9fccad88 100644 --- a/engine/botlib/q_platform.h +++ b/engine/botlib/q_platform.h @@ -88,6 +88,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define OS_STRING "win_msvc64" #elif defined __MINGW64__ #define OS_STRING "win_mingw64" +#else +#define OS_STRING "win64" #endif #define ID_INLINE static __inline diff --git a/engine/client/cl_ignore.c b/engine/client/cl_ignore.c index edd2acb5..f92f9f0b 100644 --- a/engine/client/cl_ignore.c +++ b/engine/client/cl_ignore.c @@ -27,12 +27,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MAX_TEAMIGNORELIST 4 #define FLOODLIST_SIZE 10 - - - -#define PLAYER_ID_NOMATCH -1 -#define PLAYER_NAME_NOMATCH -2 -#define PLAYER_NUM_NOMATCH -3 int Player_IdtoSlot (int id) { int j; @@ -45,7 +39,7 @@ int Player_IdtoSlot (int id) return -1; } -int Player_StringtoSlot(char *arg) +int Player_StringtoSlot(const char *arg) { int i, slot; diff --git a/engine/client/cl_ignore.h b/engine/client/cl_ignore.h index 886f7ebb..7fb96b20 100644 --- a/engine/client/cl_ignore.h +++ b/engine/client/cl_ignore.h @@ -33,4 +33,10 @@ char Ignore_Check_Flood(player_info_t *sender, const char *s, int flags); void Ignore_Flood_Add(player_info_t *sender, const char *s); void Ignore_ResetFloodList(void); + +#define PLAYER_ID_NOMATCH -1 +#define PLAYER_NAME_NOMATCH -2 +#define PLAYER_NUM_NOMATCH -3 +int Player_StringtoSlot(const char *arg); + #endif diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 820d76e9..25de9c12 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -5852,6 +5852,7 @@ void Host_Shutdown(void) #ifndef CLIENTONLY SV_Shutdown(); #else + Log_ShutDown(); NET_Shutdown (); FS_Shutdown(); #endif diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index ef4cf393..2fed51bd 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -1603,7 +1603,7 @@ void SCR_DrawGameClock(void) minutes = showtime/60; seconds = (int)showtime - (minutes*60); - sprintf(str, " %02i:%02i", minutes, seconds); + sprintf(str, "%02i:%02i", minutes, seconds); SCR_StringXY(str, show_gameclock_x.value, show_gameclock_y.value); #endif diff --git a/engine/client/net_master.c b/engine/client/net_master.c index dc9d33dc..a07e652a 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -1932,15 +1932,19 @@ int Master_CheckPollSockets(void) info = Master_InfoForServer(&net_from); if (selserver == info) { + char playeraddrbuf[256]; int playernum = MSG_ReadByte(); char *playername = MSG_ReadString(); int playercolor = MSG_ReadLong(); int playerfrags = MSG_ReadLong(); int secsonserver = MSG_ReadLong(); - //char *playeraddr = MSG_ReadString(); + char *playeraddr = MSG_ReadStringBuffer(playeraddrbuf, sizeof(playeraddrbuf)); if (msg_badread) continue; + //might as well + IPLog_Add(playeraddr, playername); + selectedserver.lastplayer = playernum+1; memset(&info->moreinfo->players[playernum], 0, sizeof(info->moreinfo->players[playernum])); diff --git a/engine/client/renderer.c b/engine/client/renderer.c index a43e4ee0..edcffa1b 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -309,9 +309,9 @@ cvar_t vid_gl_context_selfreset = CVARD ("vid_gl_context_selfreset", "1", "Upo #endif #if 1 -cvar_t gl_ati_truform = CVAR ("gl_ati_truform", "0"); +cvar_t r_tessellation = CVARAFD ("r_tessellation", "0", "gl_ati_truform", CVAR_SHADERSYSTEM, "Enables+controls the use of blinn tessellation on the fallback shader for meshes, equivelent to a shader with 'program defaultskin#TESS'. This will look stupid unless the meshes were actually designed for it and have suitable vertex normals."); cvar_t gl_ati_truform_type = CVAR ("gl_ati_truform_type", "1"); -cvar_t gl_ati_truform_tesselation = CVAR ("gl_ati_truform_tesselation", "3"); +cvar_t r_tessellation_level = CVAR ("r_tessellation_level", "5"); cvar_t gl_blend2d = CVAR ("gl_blend2d", "1"); cvar_t gl_blendsprites = CVARD ("gl_blendsprites", "0", "Blend sprites instead of alpha testing them"); cvar_t r_deluxemapping_cvar = CVARAFD ("r_deluxemapping", "0", "r_glsl_deluxemapping", @@ -497,9 +497,9 @@ void GLRenderer_Init(void) Cvar_Register (&gl_dither, GRAPHICALNICETIES); Cvar_Register (&r_fog_exp2, GLRENDEREROPTIONS); - Cvar_Register (&gl_ati_truform, GRAPHICALNICETIES); + Cvar_Register (&r_tessellation, GRAPHICALNICETIES); Cvar_Register (&gl_ati_truform_type, GRAPHICALNICETIES); - Cvar_Register (&gl_ati_truform_tesselation, GRAPHICALNICETIES); + Cvar_Register (&r_tessellation_level, GRAPHICALNICETIES); Cvar_Register (&gl_screenangle, GLRENDEREROPTIONS); diff --git a/engine/common/common.h b/engine/common/common.h index 54dd17ce..0f71ebcb 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -731,6 +731,7 @@ void Log_String (logtype_t lognum, char *s); void Con_Log (char *s); void Log_Logfile_f (void); void Log_Init(void); +void Log_ShutDown(void); void IPLog_Add(const char *ip, const char *name); //for associating player ip addresses with names. diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 51a07c9c..e6cb06a9 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -4118,8 +4118,19 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole //light grid info if (mod->lightgrid) { + char gridsize[256], *key; + char val[64]; float maxs; q3lightgridinfo_t *lg = mod->lightgrid; + key = (char*)Mod_ParseWorldspawnKey(mod, "gridsize", gridsize, sizeof(gridsize)); + + key = COM_ParseOut(key, val, sizeof(val)); + lg->gridSize[0] = atof(val); + key = COM_ParseOut(key, val, sizeof(val)); + lg->gridSize[1] = atof(val); + key = COM_ParseOut(key, val, sizeof(val)); + lg->gridSize[2] = atof(val); + if ( lg->gridSize[0] < 1 || lg->gridSize[1] < 1 || lg->gridSize[2] < 1 ) { lg->gridSize[0] = 64; diff --git a/engine/common/log.c b/engine/common/log.c index 659f013d..8fbae6f2 100644 --- a/engine/common/log.c +++ b/engine/common/log.c @@ -325,6 +325,52 @@ void SV_Fraglogfile_f (void) } */ +/*for fuck sake, why can people still not write simple files. proquake is writing binary files as text ones. this function is to try to deal with that fuckup*/ +static size_t IPLog_Read_Fucked(qbyte *file, size_t *offset, size_t totalsize, qbyte *out, size_t outsize) +{ + size_t read = 0; + while (outsize-- > 0 && *offset < totalsize) + { + if (file[*offset] == '\r' && *offset+1 < totalsize && file[*offset+1] == '\n') + { + out[read] = '\n'; + *offset += 2; + read += 1; + } + else + { + out[read] = file[*offset]; + *offset += 1; + read += 1; + } + } + return read; +} +/*need to make sure any 13 bytes followed by 10s don't bug out when read back in *sigh* */ +static size_t IPLog_Write_Fucked(vfsfile_t *file, qbyte *out, size_t outsize) +{ + qbyte tmp[64]; + size_t write = 0; + size_t block = 0; + while (outsize-- > 0) + { + if (block >= sizeof(tmp)-4) + { + VFS_WRITE(file, tmp, block); + write += block; + block = 0; + } + if (*out == '\n') + tmp[block++] = '\r'; + tmp[block++] = *out++; + } + if (block) + { + VFS_WRITE(file, tmp, block); + write += block; + } + return write; +} static qboolean IPLog_Merge_File(const char *fname) { char ip[MAX_ADR_SIZE]; @@ -333,18 +379,25 @@ static qboolean IPLog_Merge_File(const char *fname) vfsfile_t *f; if (!*fname) fname = "iplog.txt"; - f = FS_OpenVFS(fname, "rb", FS_GAME); + f = FS_OpenVFS(fname, "rb", FS_PUBBASEGAMEONLY); + if (!f) + f = FS_OpenVFS(fname, "rb", FS_GAME); if (!f) return false; - if (!Q_strcasecmp(COM_FileExtension(fname, name, sizeof(name)), ".dat")) + if (!Q_strcasecmp(COM_FileExtension(fname, name, sizeof(name)), "dat")) { //we don't write this format because of it being limited to ipv4, as well as player name lengths - while (VFS_READ(f, line, 20) == 20) - { - Q_snprintfz(ip, sizeof(ip), "%i.%i.%i.%i", (qbyte)line[0], (qbyte)line[1], (qbyte)line[2], (qbyte)line[3]); + size_t l = VFS_GETLEN(f), offset = 0; + qbyte *ffs = malloc(l+1); + VFS_READ(f, ffs, l); + ffs[l] = 0; + while (IPLog_Read_Fucked(ffs, &offset, l, line, 20) == 20) + { //yes, these addresses are weird. + Q_snprintfz(ip, sizeof(ip), "%i.%i.%i.xxx", (qbyte)line[2], (qbyte)line[1], (qbyte)line[0]); memcpy(name, line+4, 20-4); name[20-4] = 0; IPLog_Add(ip, name); } + free(ffs); } else { @@ -360,47 +413,185 @@ static qboolean IPLog_Merge_File(const char *fname) VFS_CLOSE(f); return true; } +struct iplog_entry +{ + netadr_t adr; + netadr_t mask; + char name[1]; +} **iplog_entries; +size_t iplog_num, iplog_max; void IPLog_Add(const char *ipstr, const char *name) { + size_t i; + netadr_t a, m; + while (*ipstr == ' ' || *ipstr == '\t') + ipstr++; if (*ipstr != '[' && *ipstr < '0' && *ipstr > '9') return; + if (*ipstr == '[') + ipstr++; + //some names are dodgy. + if (!*name + //|| !Q_strcasecmp(name, /*nq default*/"player") || !Q_strcasecmp(name, /*qw default*/"unnamed") + || !strcmp(name, /*nq fallback*/"unconnected") || !strncmp(name, "BOT:", 4)) + return; + memset(&a, 0, sizeof(a)); + memset(&m, 0, sizeof(m)); + if (!NET_StringToAdrMasked(ipstr, false, &a, &m)) + return; //might be x.y.z.w:port //might be x.y.z.FUCKED //might be x.y.z.0/24 //might be [::]:port //might be [::]/bits //or other ways to express an ip address - //note that ipv4 addresses should be converted to ipv6 ::ffff:x.y.z.w format for internal use or something, then this code only needs to deal with a single 128bit address format. - //ipv6 addresses generally only need 64bits to identify a user's home router, the other 64bits are generally 'just' to avoid nats. - //ignore ipx addresses, I doubt anyone will ever actually use it, and even if they do its just lans. + + //FIXME: ignore private addresses? + + //check for dupes + for (i = 0; i < iplog_num; i++) + { + if (!memcmp(&a, &iplog_entries[i]->adr, sizeof(netadr_t)) && !memcmp(&m, &iplog_entries[i]->mask, sizeof(netadr_t)) && !Q_strcasecmp(name, iplog_entries[i]->name)) + return; + } + + //looks like its new... + if (iplog_num == iplog_max) + Z_ReallocElements((void**)&iplog_entries, &iplog_max, iplog_max+64, sizeof(*iplog_entries)); + iplog_entries[iplog_num] = BZ_Malloc(sizeof(struct iplog_entry) + strlen(name)); + iplog_entries[iplog_num]->adr = a; + iplog_entries[iplog_num]->mask = m; + strcpy(iplog_entries[iplog_num]->name, name); + iplog_num++; } +static void IPLog_Identify(netadr_t *adr, netadr_t *mask, char *fmt, ...) +{ + va_list argptr; + + qboolean found = false; + char line[256]; + size_t i; + + va_start(argptr, fmt); + vsnprintf(line, sizeof(line), fmt, argptr); + va_end(argptr); + Con_Printf("%s: ", line); + + for (i = 0; i < iplog_num; i++) + { + if (NET_CompareAdrMasked(adr, &iplog_entries[i]->adr, mask?mask:&iplog_entries[i]->mask)) + { + if (found) + Con_Printf(", "); + found=true; + Con_Printf("%s", iplog_entries[i]->name); + } + } + if (!found) + Con_Printf(""); + Con_Printf("\n"); +} +#include "cl_ignore.h" static void IPLog_Identify_f(void) { -// const char *nameorip = Cmd_Argv(1); - Con_Printf("Not yet implemented\n"); + const char *nameorip = Cmd_Argv(1); + netadr_t adr, mask; + char clean[256]; //if *, use a mask that includes all ips - //try to parse as an ip - //if server is active, walk players to see if there's a name match to get their address and guess an address mask - //else if client is active, walk players to see if there's a name match, to get their address+mask if known via nq hacks - //look for matches + if (NET_StringToAdrMasked (nameorip, false, &adr, &mask)) + { //try to parse as an ip + //treading carefully here, to avoid dns name lookups weirding everything out. + IPLog_Identify(&adr, &mask, "Identity of %s", NET_AdrToStringMasked(clean, sizeof(clean), &adr, &mask)); + } +#ifndef CLIENTONLY + else if (sv.active) + { //if server is active, walk players to see if there's a name match to get their address and guess an address mask + client_t *cl; + int clnum = -1; + while((cl = SV_GetClientForString(nameorip, &clnum))) + { + if (cl->realip_status) + { + IPLog_Identify(&cl->realip, NULL, "Identity of %s (real) [%s]", cl->name, NET_AdrToString(clean, sizeof(clean), &cl->realip)); + IPLog_Identify(&cl->netchan.remote_address, NULL, "Identity of %s (proxy) [%s]", cl->name, NET_AdrToString(clean, sizeof(clean), &cl->realip)); + } + else + IPLog_Identify(&cl->netchan.remote_address, NULL, "Identity of %s [%s]", cl->name, NET_AdrToString(clean, sizeof(clean), &cl->realip)); + } + } +#endif +#ifndef SERVERONLY + else if (cls.state >= ca_connected) + { //else if client is active, walk players to see if there's a name match, to get their address+mask if known via nq hacks + int slot; + netadr_t adr; + if ((slot = Player_StringtoSlot(nameorip)) < 0) + Con_Printf("%s: no player with userid %s\n", Cmd_Argv(0), nameorip); + else if (!*cl.players[slot].ip) + Con_Printf("%s: ip address of %s is not known\n", Cmd_Argv(0), cl.players[slot].name); + else + { + NET_StringToAdr(cl.players[slot].ip, 0, &adr); + IPLog_Identify(&adr, NULL, "Identity of %s [%s]", cl.players[slot].name, cl.players[slot].ip); + } + } +#endif + else + Con_Printf("%s: not connected, nor raw address\n", Cmd_Argv(0)); +} +static qboolean IPLog_Dump(const char *fname) +{ + size_t i; + vfsfile_t *f; + qbyte line[20]; + if (!*fname) + fname = "iplog.txt"; + + f = FS_OpenVFS(fname, "wb", FS_PUBBASEGAMEONLY); + if (!f) + return false; + if (!Q_strcasecmp(COM_FileExtension(fname, line, sizeof(line)), "dat")) + { + for (i = 0; i < iplog_num; i++) + { + //this shitty format supports only ipv4. + if (iplog_entries[i]->adr.type != NA_IP) + continue; + line[0] = iplog_entries[i]->adr.address.ip[2]; + line[1] = iplog_entries[i]->adr.address.ip[1]; + line[2] = iplog_entries[i]->adr.address.ip[0]; + line[3] = 0; + strncpy(line+4, iplog_entries[i]->name, sizeof(line)-4); + IPLog_Write_Fucked(f, line, sizeof(line)); //convert \n to \r\n, to avoid fucking up any formatting with binary data (inside the address part, so *.13.10.* won't corrupt the file) + } + } + else + { + VFS_PRINTF(f, "//generated by "FULLENGINENAME"\n"); + for (i = 0; i < iplog_num; i++) + { + char ip[512]; + char buf[1024]; + char buf2[1024]; + VFS_PRINTF(f, log_dosformat.value?"%s %s\r\n":"%s %s\n", COM_QuotedString(NET_AdrToStringMasked(ip, sizeof(ip), &iplog_entries[i]->adr, &iplog_entries[i]->mask), buf2, sizeof(buf2), false), COM_QuotedString(iplog_entries[i]->name, buf, sizeof(buf), false)); + } + } + VFS_CLOSE(f); + return true; } static void IPLog_Dump_f(void) { + char native[MAX_OSPATH]; const char *fname = Cmd_Argv(1); - if (!*fname) - fname = "iplog.txt"; -#if 1 - Con_Printf("Not yet implemented\n"); -#else - vfsfile_t *f = FS_OpenVFS(fname, "wb", FS_GAMEONLY); - VFS_PRINTF(f, "//generated by "FULLENGINENAME"\n", foo->ip, foo->name); - for (foo = first; foo; foo = foo->next) + if (FS_NativePath(fname, FS_GAMEONLY, native, sizeof(native))) + Q_strncpyz(native, fname, sizeof(native)); + IPLog_Merge_File(fname); //merge from the existing file, so that we're hopefully more robust if multiple processes are poking the same file. + if (!IPLog_Dump(fname)) + Con_Printf("unable to write %s\n", fname); + else { - char buf[1024]; - VFS_PRINTF(f, "%s %s\n", foo->ip, COM_QuotedString(foo->name, buf, sizeof(buf), false)); + Con_Printf("wrote %s\n", native); } - VFS_CLOSE(f); -#endif } static void IPLog_Merge_f(void) { @@ -408,6 +599,20 @@ static void IPLog_Merge_f(void) if (!IPLog_Merge_File(fname)) Con_Printf("unable to read %s\n", fname); } +void Log_ShutDown(void) +{ + IPLog_Dump("iplog.txt"); +// IPLog_Dump("iplog.dat"); + + while(iplog_num > 0) + { + iplog_num--; + BZ_Free(iplog_entries[iplog_num]); + } + BZ_Free(iplog_entries); + iplog_entries = NULL; + iplog_max = iplog_num = 0; +} void Log_Init(void) { @@ -433,6 +638,9 @@ void Log_Init(void) Cmd_AddCommand("ipmerge", IPLog_Merge_f); Cmd_AddCommand("ipdump", IPLog_Dump_f); + IPLog_Merge_File("iplog.txt"); + IPLog_Merge_File("iplog.dat"); //legacy crap, for compat with proquake + // cmd line options, debug options #ifdef CRAZYDEBUGGING Cvar_ForceSet(&log_enable[LOG_CONSOLE], "1"); diff --git a/engine/common/net.h b/engine/common/net.h index 59f66739..a8028ec7 100644 --- a/engine/common/net.h +++ b/engine/common/net.h @@ -129,7 +129,7 @@ qboolean NET_IsClientLegal(netadr_t *adr); qboolean NET_IsLoopBackAddress (netadr_t *adr); -qboolean NET_StringToAdrMasked (const char *s, netadr_t *a, netadr_t *amask); +qboolean NET_StringToAdrMasked (const char *s, qboolean allowdns, netadr_t *a, netadr_t *amask); char *NET_AdrToStringMasked (char *s, int len, netadr_t *a, netadr_t *amask); void NET_IntegerToMask (netadr_t *a, netadr_t *amask, int bits); qboolean NET_CompareAdrMasked(netadr_t *a, netadr_t *b, netadr_t *mask); diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 4c9e7ae0..e7f92da4 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -1240,57 +1240,116 @@ void NET_IntegerToMask (netadr_t *a, netadr_t *amask, int bits) } } -// ParsePartialIPv4: check string to see if it is a partial IPv4 address and +// ParsePartialIP: check string to see if it is a partial IP address and // return bits to mask and set netadr_t or 0 if not an address -int ParsePartialIPv4(const char *s, netadr_t *a) +int ParsePartialIP(const char *s, netadr_t *a) { - const char *colon = NULL; - char *address = a->address.ip; - int bits = 8; + char *colon; + int bits; if (!*s) return 0; memset (a, 0, sizeof(*a)); - while (*s) + + //multiple colons == ipv6 + colon = strchr(s, ':'); + if (colon && strchr(colon+1, ':')) { - if (*s == ':') - { - if (colon) // only 1 colon - return 0; - colon = s + 1; - } - else if (*s == '.') - { - if (colon) // no colons before periods (probably invalid anyway) - return 0; - else if (bits >= 32) // only 32 bits in ipv4 - return 0; - else if (*(s+1) == '.') - return 0; - else if (*(s+1) == '\0') - break; // don't add more bits to the mask for x.x., etc - bits += 8; - address++; - } - else if (*s >= '0' && *s <= '9') - *address = ((*address)*10) + (*s-'0'); - else - return 0; // invalid character + qbyte *address = a->address.ip6; + unsigned long tmp; + bits = 0; + //FIXME: check for ::ffff:a.b.c.d + //FIXME: check for xx::xx - s++; + if (s[0] == ':' && s[1] == ':' && !s[2]) + { + s+=2; + bits = 1; + } + else while(*s) + { + tmp = strtoul(s, &colon, 16); + if (tmp > 0xffff) + return 0; //invalid + *address++ = (tmp>>8)&0xff; + *address++ = (tmp>>0)&0xff; + bits += 16; + + if (bits == 128) + { + if (!*colon) + break; + return 0; //must have ended here + } + + + //double-colon ends it here. we can't parse xx::xx + //hopefully the last 64 bits or whatever will be irrelevant anyway, so such addresses won't be common + if (colon[0] == ':' && colon[1] == ':' && !colon[2]) + break; + if (*colon == ':') + colon++; + else + return 0; //don't allow it if it just ended without a double-colon. + s = colon; + } + a->type = NA_IPV6; + a->port = 0; } + else + { + char *address = a->address.ip; + int port = 0; + bits = 8; + while (*s) + { + if (*s == ':') + { + port = strtoul(s+1, &address, 10); + if (*address) //if there was something other than a number there, give up now + return 0; + break; //end-of-string + } + else if (*s == '.') + { + if (bits >= 32) // only 32 bits in ipv4 + return 0; + else if (*(s+1) == '.') + return 0; + else if (*(s+1) == '\0') + break; // don't add more bits to the mask for x.x., etc + address++; - a->type = NA_IP; - if (colon) - a->port = atoi(colon); + //many nq servers mask addresses with Xs. + if (s[1] == 'x' || s[1] == 'X') + { + s++; + while (*s == 'x' || *s == 'X' || *s == '.') + s++; + if (*s) + return 0; + break; + } + bits += 8; + } + else if (*s >= '0' && *s <= '9') + *address = ((*address)*10) + (*s-'0'); + else + return 0; // invalid character + + s++; + } + a->type = NA_IP; + a->port = port; + } return bits; } // NET_StringToAdrMasked: extension to NET_StringToAdr to handle IP addresses // with masks or integers representing the bit masks -qboolean NET_StringToAdrMasked (const char *s, netadr_t *a, netadr_t *amask) +qboolean NET_StringToAdrMasked (const char *s, qboolean allowdns, netadr_t *a, netadr_t *amask) { char t[64]; char *spoint; @@ -1308,7 +1367,7 @@ qboolean NET_StringToAdrMasked (const char *s, netadr_t *a, netadr_t *amask) i = sizeof(t); Q_strncpyz(t, s, i); - if (!ParsePartialIPv4(t, a) && !NET_StringToAdr(t, 0, a)) + if (!ParsePartialIP(t, a) && (!allowdns || !NET_StringToAdr(t, 0, a))) return false; spoint++; @@ -1327,7 +1386,7 @@ qboolean NET_StringToAdrMasked (const char *s, netadr_t *a, netadr_t *amask) } if (c == NULL) // we have an address so resolve it and return - return ParsePartialIPv4(spoint, amask) || NET_StringToAdr(spoint, 0, amask); + return ParsePartialIP(spoint, amask) || (allowdns && NET_StringToAdr(spoint, 0, amask)); // otherwise generate mask for given bits i = atoi(spoint); @@ -1336,8 +1395,8 @@ qboolean NET_StringToAdrMasked (const char *s, netadr_t *a, netadr_t *amask) else { // we don't have a slash, resolve and fill with a full mask - i = ParsePartialIPv4(s, a); - if (!i && !NET_StringToAdr(s, 0, a)) + i = ParsePartialIP(s, a); + if (!i && (!allowdns || !NET_StringToAdr(s, 0, a))) return false; memset (amask, 0, sizeof(*amask)); diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index 85db516f..c45bc830 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -1004,7 +1004,6 @@ Name="VCLinkerTool" AdditionalDependencies="winmm.lib wsock32.lib Advapi32.lib" OutputFile="../../fteqwsv64.exe" - LinkIncremental="2" SuppressStartupBanner="true" AdditionalLibraryDirectories="../libs/dxsdk7/lib" IgnoreDefaultLibraryNames="libc.lib;msvcrt.lib" @@ -1079,7 +1078,7 @@ FavorSizeOrSpeed="1" OmitFramePointers="true" AdditionalIncludeDirectories="../libs/speex;..\client;../libs/freetype2/include;../common;../server;../gl;../sw;../qclib;../libs;../libs/dxsdk9/include;../libs/dxsdk7/include" - PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;GLQUAKE;D3DQUAKE;SWQUAKE;VKQUAKE" + PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;GLQUAKE;D3D9QUAKE;D3D11QUAKE;SWQUAKE;VKQUAKE;USE_EGL" StringPooling="true" RuntimeLibrary="0" EnableFunctionLevelLinking="true" @@ -10579,6 +10578,14 @@ Name="VCCLCompilerTool" /> + + + + + + texture == surf->texinfo->texture && - lbatch->shader == shader && + batch->shader == shader && batch->lightmap[0] == lmmerge(surf->lightmaptexturenums[0]) && Vector4Compare(plane, batch->plane) && batch->firstmesh + surf->mesh->numvertexes <= MAX_INDICIES && diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index eedea479..c3308095 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -71,9 +71,9 @@ extern cvar_t ffov; extern cvar_t gl_motionblur; extern cvar_t gl_motionblurscale; -extern cvar_t gl_ati_truform; +extern cvar_t r_tessellation; extern cvar_t gl_ati_truform_type; -extern cvar_t gl_ati_truform_tesselation; +extern cvar_t r_tessellation_level; extern cvar_t gl_blendsprites; extern cvar_t r_portaldrawplanes; @@ -1990,7 +1990,7 @@ void GLR_RenderView (void) qglPNTrianglesiATI(GL_PN_TRIANGLES_NORMAL_MODE_ATI, GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI); qglPNTrianglesiATI(GL_PN_TRIANGLES_POINT_MODE_ATI, GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI); } - qglPNTrianglesfATI(GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI, gl_ati_truform_tesselation.value); + qglPNTrianglesfATI(GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI, r_tessellation_level.value); } if (gl_finish.ival) diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 67c4706c..117785e6 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -46,6 +46,7 @@ extern cvar_t r_glsl_offsetmapping_reliefmapping; extern cvar_t r_fastturb, r_fastsky, r_skyboxname; extern cvar_t r_drawflat; extern cvar_t r_shaderblobs; +extern cvar_t r_tessellation; //backend fills this in to say the max pass count int be_maxpasses; @@ -1123,6 +1124,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip qboolean blobadded; qboolean geom = false; qboolean tess = false; + qboolean cantess = false; char maxgpubones[128]; cvar_t *cvarrefs[64]; @@ -1340,7 +1342,9 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip if (!permutationname[p]) { //we 'recognise' ones that are force-defined, despite not being actual permutations. - if (strncmp("SPECULAR", script, end - script)) + if (end - script == 4 && !strncmp("TESS", script, 4)) + cantess = true; + else if (strncmp("SPECULAR", script, end - script)) if (strncmp("DELUXE", script, end - script)) if (strncmp("OFFSETMAPPING", script, end - script)) if (strncmp("RELIEFMAPPING", script, end - script)) @@ -1384,6 +1388,9 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip script++; }; + if (qrenderer == qrtype && ver < 150) + tess = cantess = false; //GL_ARB_tessellation_shader requires glsl 150(gl3.2) (or glessl 3.1). nvidia complains about layouts if you try anyway + if (sh_config.pLoadBlob && blobfilename && *blobfilename) blobfile = FS_OpenVFS(blobfilename, "w+b", FS_GAMEONLY); else @@ -1448,6 +1455,9 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip prog->nofixedcompat = false; if (nummodifiers < MAXMODIFIERS) { + if (end-start == 4 && !Q_strncasecmp(start, "tess", 4)) + tess |= cantess; + permutationdefines[nummodifiers] = d = BZ_Malloc(10 + end - start); memcpy(d, "#define ", 8); memcpy(d+8, start, end - start); @@ -1537,6 +1547,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip } } + prog->tess = tess; prog->supportedpermutations = ~nopermutation; for (p = 0; p < PERMUTATIONS; p++) { @@ -4723,8 +4734,8 @@ done:; if (!s->bemoverrides[bemoverride_depthonly]) { const char *mask = Shader_AlphaMaskProgArgs(s); - if (*mask) - s->bemoverrides[bemoverride_depthonly] = R_RegisterShader(va("depthonly%s", mask), SUF_NONE, + if (*mask || (s->prog&&s->prog->tess)) + s->bemoverrides[bemoverride_depthonly] = R_RegisterShader(va("depthonly%s%s", mask, (s->prog&&s->prog->tess)?"#TESS":""), SUF_NONE, "{\n" "program depthonly\n" "{\n" @@ -4734,6 +4745,35 @@ done:; "}\n" "}\n"); } + if (!s->bemoverrides[LSHADER_STANDARD] && (s->prog&&s->prog->tess)) + { + int mode; + for (mode = 0; mode < LSHADER_MODES; mode++) + { + if ((mode & LSHADER_CUBE) && (mode & LSHADER_SPOT)) + continue; + if (s->bemoverrides[mode]) + continue; + s->bemoverrides[mode] = R_RegisterShader(va("rtlight%s%s%s%s#TESS", + (mode & LSHADER_SMAP)?"#PCF":"", + (mode & LSHADER_SPOT)?"#SPOT":"", + (mode & LSHADER_CUBE)?"#CUBE":"", +#ifdef GLQUAKE + (qrenderer == QR_OPENGL && gl_config.arb_shadow && (mode & (LSHADER_SMAP|LSHADER_SPOT)))?"#USE_ARB_SHADOW":"" +#else + "" +#endif + ) + , s->usageflags, + "{\n" + "program rtlight\n" + "{\n" + "map $diffuse\n" + "blendfunc add\n" + "}\n" + "}\n"); + } + } if (!s->prog && sh_config.progs_supported && (r_forceprogramify.ival || parsestate.forceprogramify)) { @@ -5910,6 +5950,15 @@ void Shader_DefaultSkin(const char *shortname, shader_t *s, const void *args) ); return; } + if (r_tessellation.ival && sh_config.progs_supported) + { + Shader_DefaultScript(shortname, s, + "{\n" + "program defaultskin#TESS\n" + "}\n" + ); + return; + } Shader_DefaultScript(shortname, s, "{\n" @@ -6400,7 +6449,7 @@ char *Shader_Decompose(shader_t *s) if (p->shaderbits & SBITS_MISC_NODEPTHTEST) { sprintf(o, "SBITS_MISC_NODEPTHTEST\n"); o+=strlen(o); } if (p->shaderbits & SBITS_MISC_DEPTHEQUALONLY) { sprintf(o, "SBITS_MISC_DEPTHEQUALONLY\n"); o+=strlen(o); } if (p->shaderbits & SBITS_MISC_DEPTHCLOSERONLY) { sprintf(o, "SBITS_MISC_DEPTHCLOSERONLY\n"); o+=strlen(o); } - if (p->shaderbits & SBITS_TRUFORM) { sprintf(o, "SBITS_TRUFORM\n"); o+=strlen(o); } + if (p->shaderbits & SBITS_TESSELLATION) { sprintf(o, "SBITS_TESSELLATION\n"); o+=strlen(o); } if (p->shaderbits & SBITS_AFFINE) { sprintf(o, "SBITS_AFFINE\n"); o+=strlen(o); } if (p->shaderbits & SBITS_MASK_BITS) { sprintf(o, "SBITS_MASK_BITS\n"); o+=strlen(o); } diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index b37ebcf4..a1554454 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -1217,92 +1217,91 @@ static const char *glsl_hdrs[] = "sys/defs.h", "#define DEFS_DEFINED\n" "#ifdef VERTEX_SHADER\n" -// "attribute vec3 v_position1;\n" //defined elsewhere, depending on fixed function availability -// "attribute vec3 v_position2;\n" - "attribute vec4 v_colour;\n" - "attribute vec2 v_texcoord;\n" - "attribute vec2 v_lmcoord;\n" - "attribute vec3 v_normal;\n" - "attribute vec3 v_svector;\n" - "attribute vec3 v_tvector;\n" - "attribute vec4 v_bone;\n" //fixme: make ints - "attribute vec4 v_weight;\n" +// "attribute vec3 v_position1;" //defined elsewhere, depending on fixed function availability +// "attribute vec3 v_position2;" + "attribute vec4 v_colour;" + "attribute vec2 v_texcoord;" + "attribute vec2 v_lmcoord;" + "attribute vec3 v_normal;" + "attribute vec3 v_svector;" + "attribute vec3 v_tvector;" + "attribute vec4 v_bone;" //fixme: make ints + "attribute vec4 v_weight;" #if MAXRLIGHTMAPS > 1 - "#define v_lmcoord1 v_lmcoord\n" - "attribute vec2 v_lmcoord2;\n" - "attribute vec2 v_lmcoord3;\n" - "attribute vec2 v_lmcoord4;\n" - "#define v_colour1 v_colour\n" - "attribute vec4 v_colour2;\n" - "attribute vec4 v_colour3;\n" - "attribute vec4 v_colour4;\n" + "\n#define v_lmcoord1 v_lmcoord\n" + "attribute vec2 v_lmcoord2;" + "attribute vec2 v_lmcoord3;" + "attribute vec2 v_lmcoord4;" + "\n#define v_colour1 v_colour\n" + "attribute vec4 v_colour2;" + "attribute vec4 v_colour3;" + "attribute vec4 v_colour4;" #endif - "#endif\n" + "\n#endif\n" #ifndef NOLEGACY - "uniform sampler2D s_shadowmap;\n" - "uniform samplerCube s_projectionmap;\n" - "uniform sampler2D s_diffuse;\n" - "uniform sampler2D s_normalmap;\n" - "uniform sampler2D s_specular;\n" - "uniform sampler2D s_upper;\n" - "uniform sampler2D s_lower;\n" - "uniform sampler2D s_fullbright;\n" - "uniform sampler2D s_paletted;\n" - "uniform samplerCube s_reflectcube;\n" - "uniform sampler2D s_reflectmask;\n" - "uniform sampler2D s_lightmap;\n" - "uniform sampler2D s_deluxmap;\n" - "#define s_lightmap0 s_lightmap\n" + "uniform sampler2DShadow s_shadowmap;" + "uniform samplerCube s_projectionmap;" + "uniform sampler2D s_diffuse;" + "uniform sampler2D s_normalmap;" + "uniform sampler2D s_specular;" + "uniform sampler2D s_upper;" + "uniform sampler2D s_lower;" + "uniform sampler2D s_fullbright;" + "uniform sampler2D s_paletted;" + "uniform samplerCube s_reflectcube;" + "uniform sampler2D s_reflectmask;" + "uniform sampler2D s_lightmap;" + "uniform sampler2D s_deluxmap;" + "\n#define s_lightmap0 s_lightmap\n" "#define s_deluxmap0 s_deluxmap\n" #if MAXRLIGHTMAPS > 1 - "uniform sampler2D s_lightmap1;\n" - "uniform sampler2D s_lightmap2;\n" - "uniform sampler2D s_lightmap3;\n" - "uniform sampler2D s_deluxmap1;\n" - "uniform sampler2D s_deluxmap2;\n" + "uniform sampler2D s_lightmap1;" + "uniform sampler2D s_lightmap2;" + "uniform sampler2D s_lightmap3;" + "uniform sampler2D s_deluxmap1;" + "uniform sampler2D s_deluxmap2;" "uniform sampler2D s_deluxmap3;\n" #endif #endif "#ifdef USEUBOS\n" "layout(std140) uniform u_lightinfo\n" - "{\n" - "vec3 l_lightscreen;\n" - "float l_lightradius;\n" - "vec3 l_lightcolour;\n" + "{" + "vec3 l_lightscreen;" + "float l_lightradius;" + "vec3 l_lightcolour;" "float l_pad1;\n" - "vec3 l_lightcolourscale;\n" - "float l_pad2;\n" - "vec3 l_lightposition;\n" - "float l_pad3;\n" - "mat4 l_cubematrix;\n" - "vec4 l_shadowmapproj;\n" - "vec2 l_shadowmapscale;\n" - "vec2 l_pad4;\n" - "\n" + "vec3 l_lightcolourscale;n" + "float l_pad2;" + "vec3 l_lightposition;" + "float l_pad3;" + "mat4 l_cubematrix;" + "vec4 l_shadowmapproj;" + "vec2 l_shadowmapscale;" + "vec2 l_pad4;" "};\n" "layout(std140) uniform u_entityinfo\n" "{\n" - "vec2 e_vblend;\n" - "vec2 e_pad1;\n" - "vec3 e_glowmod;\n" - "float e_pad2;\n" - "vec3 e_origin;\n" - "float e_pad3;\n" - "vec4 colormod;\n" - "vec3 e_glowmod;\n" - "float e_pad4;\n" - "vec3 e_uppercolour;\n" - "float e_pad5;\n" - "vec3 e_lowercolour;\n" - "float e_pad6;\n" - "vec3 w_fogcolour;\n" - "float w_fogalpha;\n" - "vec3 e_light_dir;\n" - "float w_fogdensity;\n" - "vec3 e_light_mul;\n" - "float w_fogdepthbias;\n" - "vec3 e_light_ambient;\n" - "float e_time;\n" + "vec2 e_vblend;" + "vec2 e_pad1;" + "vec3 e_glowmod;" + "float e_pad2;" + "vec3 e_origin;" + "float e_pad3;" + "vec4 colormod;" + "vec3 e_glowmod;" + "float e_pad4;" + "vec3 e_uppercolour;" + "float e_pad5;" + "vec3 e_lowercolour;" + "float e_pad6;" + "vec3 w_fogcolour;" + "float w_fogalpha;" + "vec3 e_light_dir;" + "float w_fogdensity;" + "vec3 e_light_mul;" + "float w_fogdepthbias;" + "vec3 e_light_ambient;" + "float e_time;" "};\n" "#ifdef SKELETAL\n" "layout(std140) unform u_bones\n" @@ -1315,11 +1314,13 @@ static const char *glsl_hdrs[] = "};\n" "#endif\n" "#else\n" - "uniform mat4 m_model;\n" - "uniform mat4 m_view;\n" - "uniform mat4 m_modelview;\n" + "uniform mat4 m_model;" + "uniform mat4 m_view;" + "uniform mat4 m_modelview;" "uniform mat4 m_projection;\n" -// "uniform mat4 m_modelviewprojection;\n" + "#ifndef VERTEX_SHADER\n" + "uniform mat4 m_modelviewprojection;\n" + "#endif\n" "#ifdef SKELETAL\n" //skeletal permutation tends to require glsl 120 "#ifdef PACKEDBONES\n" "uniform vec4 m_bones[3*MAX_GPU_BONES];\n" @@ -1327,11 +1328,11 @@ static const char *glsl_hdrs[] = "uniform mat3x4 m_bones[MAX_GPU_BONES];\n" "#endif\n" "#endif\n" - "uniform mat4 m_invviewprojection;\n" - "uniform mat4 m_invmodelviewprojection;\n" + "uniform mat4 m_invviewprojection;" + "uniform mat4 m_invmodelviewprojection;" /*viewer properties*/ - "uniform vec3 v_eyepos;\n" + "uniform vec3 v_eyepos;" "uniform vec4 w_fog[2];\n" "#define w_fogcolour w_fog[0].rgb\n" "#define w_fogalpha w_fog[0].a\n" @@ -1345,37 +1346,37 @@ static const char *glsl_hdrs[] = "#else\n" "uniform vec4 e_lmscale;\n" "#endif\n" - "uniform vec3 e_origin;\n" - "uniform float e_time;\n" - "uniform vec3 e_eyepos;\n" - "uniform vec4 e_colour;\n" - "uniform vec4 e_colourident;\n" - "uniform vec3 e_glowmod;\n" - "uniform vec3 e_uppercolour;\n" - "uniform vec3 e_lowercolour;\n" - "uniform vec3 e_light_dir;\n" - "uniform vec3 e_light_mul;\n" - "uniform vec3 e_light_ambient;\n" + "uniform vec3 e_origin;" + "uniform float e_time;" + "uniform vec3 e_eyepos;" + "uniform vec4 e_colour;" + "uniform vec4 e_colourident;" + "uniform vec3 e_glowmod;" + "uniform vec3 e_uppercolour;" + "uniform vec3 e_lowercolour;" + "uniform vec3 e_light_dir;" + "uniform vec3 e_light_mul;" + "uniform vec3 e_light_ambient;" /*rtlight properties, use with caution*/ - "uniform vec2 l_lightscreen;\n" - "uniform float l_lightradius;\n" - "uniform vec3 l_lightcolour;\n" - "uniform vec3 l_lightposition;\n" - "uniform vec3 l_lightcolourscale;\n" - "uniform mat4 l_cubematrix;\n" - "uniform vec4 l_shadowmapproj;\n" - "uniform vec2 l_shadowmapscale;\n" + "uniform vec2 l_lightscreen;" + "uniform float l_lightradius;" + "uniform vec3 l_lightcolour;" + "uniform vec3 l_lightposition;" + "uniform vec3 l_lightcolourscale;" + "uniform mat4 l_cubematrix;" + "uniform vec4 l_shadowmapproj;" + "uniform vec2 l_shadowmapscale;" "uniform vec2 e_rendertexturescale;\n" "#endif\n" , "sys/skeletal.h", "#ifndef DEFS_DEFINED\n" - "attribute vec3 v_normal;\n" - "attribute vec3 v_svector;\n" - "attribute vec3 v_tvector;\n" - "#endif\n" + "attribute vec3 v_normal;" + "attribute vec3 v_svector;" + "attribute vec3 v_tvector;" + "\n#endif\n" "#ifdef SKELETAL\n" "#ifndef DEFS_DEFINED\n" "attribute vec4 v_bone;" @@ -1887,10 +1888,18 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int length[strings] = strlen(prstrings[strings]); strings++; } - if (ver >= 130) //gl3+ deprecated the varying keyword for geometry shaders to work properly + if (ver >= 130) { prstrings[strings] = + //gl3+ deprecated the varying keyword for geometry shaders to work properly "#define varying in\n" + //it also deprecated the numerous texture functions. now only the 'texture' function exists, with overloads for each sampler type. + "#define texture2D texture\n" + "#define textureCube texture\n" + "#define shadow2D texture\n" + //gl_FragColor and gl_FragData got deprecated too + "out vec4 fte_fragdata;\n" + "#define gl_FragColor fte_fragdata\n" ; length[strings] = strlen(prstrings[strings]); strings++; @@ -1912,7 +1921,7 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int #ifdef NOLEGACY const char *defaultsamplernames[] = { - "uniform sampler2D s_shadowmap;\n", + "uniform sampler2DShadow s_shadowmap;\n", "uniform samplerCube s_projectionmap;\n", "uniform sampler2D s_diffuse;\n", "uniform sampler2D s_normalmap;\n", @@ -1957,12 +1966,22 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int strings++; break; case GL_TESS_CONTROL_SHADER_ARB: - prstrings[strings] = "#define TESS_CONTROL_SHADER\n"; + prstrings[strings] = + "#define TESS_CONTROL_SHADER\n" + "#if __VERSION__ < 400\n" + "#extension GL_ARB_tessellation_shader : enable\n" + "#endif\n"; + //varyings are arrays, so don't bother defining that here. length[strings] = strlen(prstrings[strings]); strings++; break; case GL_TESS_EVALUATION_SHADER_ARB: - prstrings[strings] = "#define TESS_EVALUATION_SHADER\n"; + prstrings[strings] = + "#define TESS_EVALUATION_SHADER\n" + "#if __VERSION__ < 400\n" + "#extension GL_ARB_tessellation_shader : enable\n" + "#endif\n" + "#define varying out\n"; length[strings] = strlen(prstrings[strings]); strings++; break; @@ -2084,7 +2103,7 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int //called after CreateShader. Checks for success. //Splitting creation allows for both vertex+fragment shaders to be processed simultaneously if the driver threads glCompileShaderARB. -static GLhandleARB GLSlang_FinishShader(GLhandleARB shader, const char *name, GLenum shadertype, qboolean silent) +static GLhandleARB GLSlang_FinishShader(GLhandleARB shader, const char *name, GLenum shadertype, qboolean *silent) { GLint compiled; int loglen; @@ -2096,12 +2115,13 @@ static GLhandleARB GLSlang_FinishShader(GLhandleARB shader, const char *name, GL if(!compiled) { char *typedesc; - char str[8192]; + char str[65536]; *str = 0; qglGetShaderInfoLog_(shader, sizeof(str), NULL, str); - if (!silent) + if (!*silent) { + *silent = true; switch (shadertype) { case GL_FRAGMENT_SHADER_ARB: @@ -2168,7 +2188,7 @@ static GLhandleARB GLSlang_FinishShader(GLhandleARB shader, const char *name, GL return shader; } -GLhandleARB GLSlang_CreateProgramObject (const char *name, GLhandleARB vert, GLhandleARB cont, GLhandleARB eval, GLhandleARB geom, GLhandleARB frag, qboolean silent) +GLhandleARB GLSlang_CreateProgramObject (const char *name, GLhandleARB vert, GLhandleARB cont, GLhandleARB eval, GLhandleARB geom, GLhandleARB frag) { GLhandleARB program; @@ -2295,16 +2315,16 @@ union programhandle_u GLSlang_CreateProgram(program_t *prog, const char *name, i cs = GLSlang_CreateShader(prog, name, ver, precompilerconstants, cont, GL_TESS_CONTROL_SHADER_ARB, silent); es = GLSlang_CreateShader(prog, name, ver, precompilerconstants, eval, GL_TESS_EVALUATION_SHADER_ARB, silent); - fs = GLSlang_FinishShader(fs, name, GL_FRAGMENT_SHADER_ARB, silent); - gs = GLSlang_FinishShader(gs, name, GL_GEOMETRY_SHADER_ARB, silent); - vs = GLSlang_FinishShader(vs, name, GL_VERTEX_SHADER_ARB, silent); - cs = GLSlang_FinishShader(cs, name, GL_TESS_CONTROL_SHADER_ARB, silent); - es = GLSlang_FinishShader(es, name, GL_TESS_EVALUATION_SHADER_ARB, silent); + fs = GLSlang_FinishShader(fs, name, GL_FRAGMENT_SHADER_ARB, &silent); + gs = GLSlang_FinishShader(gs, name, GL_GEOMETRY_SHADER_ARB, &silent); + vs = GLSlang_FinishShader(vs, name, GL_VERTEX_SHADER_ARB, &silent); + cs = GLSlang_FinishShader(cs, name, GL_TESS_CONTROL_SHADER_ARB, &silent); + es = GLSlang_FinishShader(es, name, GL_TESS_EVALUATION_SHADER_ARB, &silent); if (!vs || !fs) ret.glsl.handle = 0; else - ret.glsl.handle = GLSlang_CreateProgramObject(name, vs, cs, es, gs, fs, silent); + ret.glsl.handle = GLSlang_CreateProgramObject(name, vs, cs, es, gs, fs); //delete ignores 0s. if (vs) qglDeleteShaderObject_(vs); if (gs) qglDeleteShaderObject_(gs); @@ -2314,6 +2334,7 @@ union programhandle_u GLSlang_CreateProgram(program_t *prog, const char *name, i checkglerror(); + ret.glsl.usetesselation = (cont || eval); if (ret.glsl.handle && blobfile && qglGetProgramBinary) { GLuint ui; @@ -2335,8 +2356,6 @@ union programhandle_u GLSlang_CreateProgram(program_t *prog, const char *name, i BZ_Free(blobdata); } - ret.glsl.usetesselation = (cont || eval); - return ret; } diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index 90183a41..2005ce14 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -1849,8 +1849,13 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #endif #ifdef GLQUAKE {QR_OPENGL, 110, "depthonly", +"!!ver 100 150\n" +"!!permu TESS\n" "!!permu FRAMEBLEND\n" "!!permu SKELETAL\n" +"!!cvardf r_tessellation=0\n" + +"#include \"sys/defs.h\"\n" //standard shader used for drawing shadowmap depth. //also used for masking off portals and other things that want depth and no colour. @@ -1859,12 +1864,80 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#ifdef VERTEX_SHADER\n" "#include \"sys/skeletal.h\"\n" +"#ifdef TESS\n" +"varying vec3 vertex;\n" +"varying vec3 normal;\n" +"#endif\n" "void main ()\n" "{\n" +"#ifdef TESS\n" +"skeletaltransform_n(normal);\n" +"vertex = v_position;\n" +"#else\n" "gl_Position = skeletaltransform();\n" +"#endif\n" "}\n" "#endif\n" + + +"#if defined(TESS_CONTROL_SHADER)\n" +"layout(vertices = 3) out;\n" + +"in vec3 vertex[];\n" +"out vec3 t_vertex[];\n" +"in vec3 normal[];\n" +"out vec3 t_normal[];\n" + +"void main()\n" +"{\n" +//the control shader needs to pass stuff through +"#define id gl_InvocationID\n" +"t_vertex[id] = vertex[id];\n" +"t_normal[id] = normal[id];\n" +"gl_TessLevelOuter[0] = float(r_tessellation)+1.0;\n" +"gl_TessLevelOuter[1] = float(r_tessellation)+1.0;\n" +"gl_TessLevelOuter[2] = float(r_tessellation)+1.0;\n" +"gl_TessLevelInner[0] = float(r_tessellation)+1.0;\n" +"}\n" +"#endif\n" + + + + + + + + + +"#if defined(TESS_EVALUATION_SHADER)\n" +"layout(triangles) in;\n" + +"in vec3 t_vertex[];\n" +"in vec3 t_normal[];\n" + +"#define LERP(a) (gl_TessCoord.x*a[0] + gl_TessCoord.y*a[1] + gl_TessCoord.z*a[2])\n" +"void main()\n" +"{\n" +"#define factor 1.0\n" +"vec3 w = LERP(t_vertex);\n" + +"vec3 t0 = w - dot(w-t_vertex[0],t_normal[0])*t_normal[0];\n" +"vec3 t1 = w - dot(w-t_vertex[1],t_normal[1])*t_normal[1];\n" +"vec3 t2 = w - dot(w-t_vertex[2],t_normal[2])*t_normal[2];\n" +"w = w*(1.0-factor) + factor*(gl_TessCoord.x*t0+gl_TessCoord.y*t1+gl_TessCoord.z*t2);\n" + +"gl_Position = m_modelviewprojection * vec4(w,1.0);\n" +"}\n" +"#endif\n" + + + + + + + + "#ifdef FRAGMENT_SHADER\n" "void main ()\n" "{\n" @@ -2248,7 +2321,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #endif #ifdef GLQUAKE {QR_OPENGL, 110, "defaultskin", -"!!ver 100 130\n" +"!!ver 100 150\n" +"!!permu TESS\n" "!!permu FULLBRIGHT\n" "!!permu UPPERLOWER\n" "!!permu FRAMEBLEND\n" @@ -2258,6 +2332,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "!!cvarf r_glsl_offsetmapping_scale\n" "!!cvarf gl_specular\n" "!!cvardf gl_affinemodels=0\n" +"!!cvardf r_tessellation=0\n" "#include \"sys/defs.h\"\n" @@ -2266,19 +2341,31 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND //the vertex shader is responsible for calculating lighting values. "#if gl_affinemodels==1 && __VERSION__ >= 130\n" -"noperspective\n" -"#endif\n" -"varying vec2 tc;\n" -"varying vec3 light;\n" -"#if defined(SPECULAR) || defined(OFFSETMAPPING)\n" -"varying vec3 eyevector;\n" +"#define affine noperspective\n" +"#else\n" +"#define affine\n" "#endif\n" + + + + "#ifdef VERTEX_SHADER\n" "#include \"sys/skeletal.h\"\n" + +"affine varying vec2 tc;\n" +"varying vec3 light;\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING)\n" +"varying vec3 eyevector;\n" +"#endif\n" +"#ifdef TESS\n" +"varying vec3 vertex;\n" +"varying vec3 normal;\n" +"#endif\n" + "void main ()\n" "{\n" "#if defined(SPECULAR)||defined(OFFSETMAPPING)\n" @@ -2289,17 +2376,120 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "eyevector.y = dot(eyeminusvertex, t.xyz);\n" "eyevector.z = dot(eyeminusvertex, n.xyz);\n" "#else\n" -"vec3 n;\n" -"gl_Position = skeletaltransform_n(n);\n" +"vec3 n, s, t, w;\n" +"gl_Position = skeletaltransform_wnst(w,n,s,t);\n" "#endif\n" +"tc = v_texcoord;\n" + "float d = dot(n,e_light_dir);\n" "if (d < 0.0) //vertex shader. this might get ugly, but I don't really want to make it per vertex.\n" "d = 0.0; //this avoids the dark side going below the ambient level.\n" "light = e_light_ambient + (dot(n,e_light_dir)*e_light_mul);\n" -"tc = v_texcoord;\n" + +"#ifdef TESS\n" +"normal = n;\n" +"vertex = w;\n" +"#endif\n" "}\n" "#endif\n" + + + + + + + + + + +"#if defined(TESS_CONTROL_SHADER)\n" +"layout(vertices = 3) out;\n" + +"in vec3 vertex[];\n" +"out vec3 t_vertex[];\n" +"in vec3 normal[];\n" +"out vec3 t_normal[];\n" +"affine in vec2 tc[];\n" +"affine out vec2 t_tc[];\n" +"in vec3 light[];\n" +"out vec3 t_light[];\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING)\n" +"in vec3 eyevector[];\n" +"out vec3 t_eyevector[];\n" +"#endif\n" +"void main()\n" +"{\n" +//the control shader needs to pass stuff through +"#define id gl_InvocationID\n" +"t_vertex[id] = vertex[id];\n" +"t_normal[id] = normal[id];\n" +"t_tc[id] = tc[id];\n" +"t_light[id] = light[id];\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING)\n" +"t_eyevector[id] = eyevector[id];\n" +"#endif\n" + +"gl_TessLevelOuter[0] = float(r_tessellation)+1.0;\n" +"gl_TessLevelOuter[1] = float(r_tessellation)+1.0;\n" +"gl_TessLevelOuter[2] = float(r_tessellation)+1.0;\n" +"gl_TessLevelInner[0] = float(r_tessellation)+1.0;\n" +"}\n" +"#endif\n" + + + + + + + + + +"#if defined(TESS_EVALUATION_SHADER)\n" +"layout(triangles) in;\n" + +"in vec3 t_vertex[];\n" +"in vec3 t_normal[];\n" +"affine in vec2 t_tc[];\n" +"affine out vec2 tc;\n" +"in vec3 t_light[];\n" +"out vec3 light;\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING)\n" +"in vec3 t_eyevector[];\n" +"out vec3 eyevector;\n" +"#endif\n" + +"#define LERP(a) (gl_TessCoord.x*a[0] + gl_TessCoord.y*a[1] + gl_TessCoord.z*a[2])\n" +"void main()\n" +"{\n" +"#define factor 1.0\n" +"tc = LERP(t_tc);\n" +"vec3 w = LERP(t_vertex);\n" + +"vec3 t0 = w - dot(w-t_vertex[0],t_normal[0])*t_normal[0];\n" +"vec3 t1 = w - dot(w-t_vertex[1],t_normal[1])*t_normal[1];\n" +"vec3 t2 = w - dot(w-t_vertex[2],t_normal[2])*t_normal[2];\n" +"w = w*(1.0-factor) + factor*(gl_TessCoord.x*t0+gl_TessCoord.y*t1+gl_TessCoord.z*t2);\n" + +//FIXME: we should be recalcing these here, instead of just lerping them +"light = LERP(t_light);\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING)\n" +"eyevector = LERP(t_eyevector);\n" +"#endif\n" + +"gl_Position = m_modelviewprojection * vec4(w,1.0);\n" +"}\n" +"#endif\n" + + + + + + + + + + "#ifdef FRAGMENT_SHADER\n" "#include \"sys/fog.h\"\n" @@ -2317,9 +2507,10 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "uniform sampler2D s_colourmap;\n" "#endif\n" -"#if __VERSION__ >= 130\n" -"#define gl_FragColor thecolour\n" -"out vec4 thecolour;\n" +"affine varying vec2 tc;\n" +"varying vec3 light;\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING)\n" +"varying vec3 eyevector;\n" "#endif\n" @@ -4483,7 +4674,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #endif #ifdef GLQUAKE {QR_OPENGL, 110, "defaultwall", -"!!ver 100 120 // 130\n" +"!!ver 100 150\n" +"!!permu TESS\n" "!!permu DELUXE\n" "!!permu FULLBRIGHT\n" "!!permu FOG\n" @@ -4493,19 +4685,16 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "!!permu REFLECTCUBEMASK\n" "!!cvarf r_glsl_offsetmapping_scale\n" "!!cvarf gl_specular\n" +"!!cvardf r_tessellation=0\n" "#include \"sys/defs.h\"\n" -"#if __VERSION__ >= 130\n" -"#define texture2D texture\n" -"#define textureCube texture\n" -"#define gl_FragColor gl_FragData[0]\n" -"#endif\n" - //this is what normally draws all of your walls, even with rtlights disabled //note that the '286' preset uses drawflat_walls instead. "#include \"sys/fog.h\"\n" + +"#if !defined(TESS_CONTROL_SHADER)\n" "#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK)\n" "varying vec3 eyevector;\n" "#endif\n" @@ -4526,8 +4715,12 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "varying vec2 lm0;\n" "#endif\n" "#endif\n" +"#endif\n" "#ifdef VERTEX_SHADER\n" +"#ifdef TESS\n" +"varying vec3 vertex, normal;\n" +"#endif\n" "void main ()\n" "{\n" "#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK)\n" @@ -4558,10 +4751,151 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#endif\n" "#endif\n" "gl_Position = ftetransform();\n" + +"#ifdef TESS\n" +"vertex = v_position;\n" +"normal = v_normal;\n" +"#endif\n" "}\n" "#endif\n" +"#if defined(TESS_CONTROL_SHADER)\n" +"layout(vertices = 3) out;\n" + +"in vec3 vertex[];\n" +"out vec3 t_vertex[];\n" +"in vec3 normal[];\n" +"out vec3 t_normal[];\n" +"#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK)\n" +"in vec3 eyevector[];\n" +"out vec3 t_eyevector[];\n" +"#endif\n" +"#ifdef REFLECTCUBEMASK\n" +"in mat3 invsurface[];\n" +"out mat3 t_invsurface[];\n" +"#endif\n" +"in vec2 tc[];\n" +"out vec2 t_tc[];\n" +"#ifdef VERTEXLIT\n" +"in vec4 vc[];\n" +"out vec4 t_vc[];\n" +"#else\n" +"in vec2 lm0[];\n" +"out vec2 t_lm0[];\n" +"#ifdef LIGHTSTYLED\n" +"in vec2 lm1[], lm2[], lm3[];\n" +"out vec2 t_lm1[], t_lm2[], t_lm3[];\n" +"#endif\n" +"#endif\n" +"void main()\n" +"{\n" +//the control shader needs to pass stuff through +"#define id gl_InvocationID\n" +"t_vertex[id] = vertex[id];\n" +"t_normal[id] = normal[id];\n" +"#ifdef REFLECTCUBEMASK\n" +"t_invsurface[id] = invsurface[id];\n" +"#endif\n" +"t_tc[id] = tc[id];\n" +"#ifdef VERTEXLIT\n" +"t_vc[id] = vc[id];\n" +"#else\n" +"t_lm0[id] = lm0[id];\n" +"#ifdef LIGHTSTYLED\n" +"t_lm1[id] = lm1[id];\n" +"t_lm2[id] = lm2[id];\n" +"t_lm3[id] = lm3[id];\n" +"#endif\n" +"#endif\n" + +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"t_eyevector[id] = eyevector[id];\n" +"#endif\n" + +"gl_TessLevelOuter[0] = float(r_tessellation)+1.0;\n" +"gl_TessLevelOuter[1] = float(r_tessellation)+1.0;\n" +"gl_TessLevelOuter[2] = float(r_tessellation)+1.0;\n" +"gl_TessLevelInner[0] = float(r_tessellation)+1.0;\n" +"}\n" +"#endif\n" + + + + + + + + + +"#if defined(TESS_EVALUATION_SHADER)\n" +"layout(triangles) in;\n" + +"in vec3 t_vertex[];\n" +"in vec3 t_normal[];\n" +"#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK)\n" +"in vec3 t_eyevector[];\n" +"#endif\n" +"#ifdef REFLECTCUBEMASK\n" +"in mat3 t_invsurface[];\n" +"#endif\n" +"in vec2 t_tc[];\n" +"#ifdef VERTEXLIT\n" +"in vec4 t_vc[];\n" +"#else\n" +"#ifdef LIGHTSTYLED\n" +//we could use an offset, but that would still need to be per-surface which would break batches +//fixme: merge attributes? +"in vec2 t_lm0[], t_lm1[], t_lm2[], t_lm3[];\n" +"#else\n" +"in vec2 t_lm0[];\n" +"#endif\n" +"#endif\n" + +"#define LERP(a) (gl_TessCoord.x*a[0] + gl_TessCoord.y*a[1] + gl_TessCoord.z*a[2])\n" +"void main()\n" +"{\n" +"#define factor 1.0\n" +"tc = LERP(t_tc);\n" +"#ifdef VERTEXLIT\n" +"vc = LERP(t_vc);\n" +"#else\n" +"lm0 = LERP(t_lm0);\n" +"#ifdef LIGHTSTYLED\n" +"lm1 = LERP(t_lm1);\n" +"lm2 = LERP(t_lm2);\n" +"lm3 = LERP(t_lm3);\n" +"#endif\n" +"#endif\n" +"vec3 w = LERP(t_vertex);\n" + +"vec3 t0 = w - dot(w-t_vertex[0],t_normal[0])*t_normal[0];\n" +"vec3 t1 = w - dot(w-t_vertex[1],t_normal[1])*t_normal[1];\n" +"vec3 t2 = w - dot(w-t_vertex[2],t_normal[2])*t_normal[2];\n" +"w = w*(1.0-factor) + factor*(gl_TessCoord.x*t0+gl_TessCoord.y*t1+gl_TessCoord.z*t2);\n" + +"#if defined(PCF) || defined(SPOT) || defined(CUBE)\n" +//for texture projections/shadowmapping on dlights +"vtexprojcoord = (l_cubematrix*vec4(w.xyz, 1.0));\n" +"#endif\n" + +//FIXME: we should be recalcing these here, instead of just lerping them +"#ifdef REFLECTCUBEMASK\n" +"invsurface = LERP(t_invsurface);\n" +"#endif\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"eyevector = LERP(t_eyevector);\n" +"#endif\n" + +"gl_Position = m_modelviewprojection * vec4(w,1.0);\n" +"}\n" +"#endif\n" + + + + + + "#ifdef FRAGMENT_SHADER\n" //samplers @@ -9302,6 +9636,8 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #endif #ifdef GLQUAKE {QR_OPENGL, 110, "rtlight", +"!!ver 100 150\n" +"!!permu TESS\n" "!!permu BUMP\n" "!!permu FRAMEBLEND\n" "!!permu SKELETAL\n" @@ -9310,7 +9646,9 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "!!permu REFLECTCUBEMASK\n" "!!cvarf r_glsl_offsetmapping_scale\n" "!!cvardf r_glsl_pcf\n" +"!!cvardf r_tessellation=0\n" +"#include \"sys/defs.h\"\n" "#ifndef USE_ARB_SHADOW\n" //fall back on regular samplers if we must @@ -9352,7 +9690,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#undef OFFSETMAPPING\n" "#endif\n" - +"#if !defined(TESS_CONTROL_SHADER)\n" "varying vec2 tcbase;\n" "varying vec3 lightvector;\n" "#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" @@ -9360,23 +9698,18 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#endif\n" "#ifdef REFLECTCUBEMASK\n" "varying mat3 invsurface;\n" -"uniform mat4 m_model;\n" "#endif\n" "#if defined(PCF) || defined(CUBE) || defined(SPOT)\n" "varying vec4 vtexprojcoord;\n" "#endif\n" +"#endif\n" "#ifdef VERTEX_SHADER\n" -"#if defined(PCF) || defined(CUBE) || defined(SPOT)\n" -"uniform mat4 l_cubematrix;\n" +"#ifdef TESS\n" +"varying vec3 vertex, normal;\n" "#endif\n" "#include \"sys/skeletal.h\"\n" -"uniform vec3 l_lightposition;\n" -"attribute vec2 v_texcoord;\n" -"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" -"uniform vec3 e_eyepos;\n" -"#endif\n" "void main ()\n" "{\n" "vec3 n, s, t, w;\n" @@ -9407,57 +9740,114 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND //for texture projections/shadowmapping on dlights "vtexprojcoord = (l_cubematrix*vec4(w.xyz, 1.0));\n" "#endif\n" + +"#ifdef TESS\n" +"vertex = w;\n" +"normal = n;\n" +"#endif\n" "}\n" "#endif\n" + + +"#if defined(TESS_CONTROL_SHADER)\n" +"layout(vertices = 3) out;\n" + +"in vec3 vertex[];\n" +"out vec3 t_vertex[];\n" +"in vec3 normal[];\n" +"out vec3 t_normal[];\n" +"in vec2 tcbase[];\n" +"out vec2 t_tcbase[];\n" +"in vec3 lightvector[];\n" +"out vec3 t_lightvector[];\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"in vec3 eyevector[];\n" +"out vec3 t_eyevector[];\n" +"#endif\n" +"void main()\n" +"{\n" +//the control shader needs to pass stuff through +"#define id gl_InvocationID\n" +"t_vertex[id] = vertex[id];\n" +"t_normal[id] = normal[id];\n" +"t_tcbase[id] = tcbase[id];\n" +"t_lightvector[id] = lightvector[id];\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"t_eyevector[id] = eyevector[id];\n" +"#endif\n" + +"gl_TessLevelOuter[0] = float(r_tessellation)+1.0;\n" +"gl_TessLevelOuter[1] = float(r_tessellation)+1.0;\n" +"gl_TessLevelOuter[2] = float(r_tessellation)+1.0;\n" +"gl_TessLevelInner[0] = float(r_tessellation)+1.0;\n" +"}\n" +"#endif\n" + + + + + + + + + +"#if defined(TESS_EVALUATION_SHADER)\n" +"layout(triangles) in;\n" + +"in vec3 t_vertex[];\n" +"in vec3 t_normal[];\n" +"in vec2 t_tcbase[];\n" +"in vec3 t_lightvector[];\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"in vec3 t_eyevector[];\n" +"#endif\n" + +"#define LERP(a) (gl_TessCoord.x*a[0] + gl_TessCoord.y*a[1] + gl_TessCoord.z*a[2])\n" +"void main()\n" +"{\n" +"#define factor 1.0\n" +"tcbase = LERP(t_tcbase);\n" +"vec3 w = LERP(t_vertex);\n" + +"vec3 t0 = w - dot(w-t_vertex[0],t_normal[0])*t_normal[0];\n" +"vec3 t1 = w - dot(w-t_vertex[1],t_normal[1])*t_normal[1];\n" +"vec3 t2 = w - dot(w-t_vertex[2],t_normal[2])*t_normal[2];\n" +"w = w*(1.0-factor) + factor*(gl_TessCoord.x*t0+gl_TessCoord.y*t1+gl_TessCoord.z*t2);\n" + +"#if defined(PCF) || defined(SPOT) || defined(CUBE)\n" +//for texture projections/shadowmapping on dlights +"vtexprojcoord = (l_cubematrix*vec4(w.xyz, 1.0));\n" +"#endif\n" + +//FIXME: we should be recalcing these here, instead of just lerping them +"lightvector = LERP(t_lightvector);\n" +"#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" +"eyevector = LERP(t_eyevector);\n" +"#endif\n" + +"gl_Position = m_modelviewprojection * vec4(w,1.0);\n" +"}\n" +"#endif\n" + + + + + + + + + + + "#ifdef FRAGMENT_SHADER\n" + "#include \"sys/fog.h\"\n" -"uniform sampler2D s_diffuse; //diffuse\n" -"#if defined(BUMP) || defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK)\n" -"uniform sampler2D s_normalmap; //normalmap\n" -"#endif\n" -"#ifdef SPECULAR\n" -"uniform sampler2D s_specular; //specular\n" -"#endif\n" -"#ifdef CUBE\n" -"uniform samplerCube s_projectionmap; //projected cubemap\n" -"#endif\n" "#ifdef PCF\n" -"#ifdef CUBESHADOW\n" -"uniform samplerCubeShadow s_shadowmap; //shadowmap\n" -"#else\n" -"#if 0//def GL_ARB_texture_gather\n" -"uniform sampler2D s_shadowmap;\n" -"#else\n" -"uniform sampler2DShadow s_shadowmap;\n" -"#endif\n" -"#endif\n" -"#endif\n" -"#ifdef LOWER\n" -"uniform sampler2D s_lower; //pants colours\n" -"uniform vec3 e_lowercolour;\n" -"#endif\n" -"#ifdef UPPER\n" -"uniform sampler2D s_upper; //shirt colours\n" -"uniform vec3 e_uppercolour;\n" -"#endif\n" - -"#ifdef REFLECTCUBEMASK\n" -"uniform sampler2D s_reflectmask;\n" -"uniform samplerCube s_reflectcube;\n" -"#endif\n" - - -"uniform float l_lightradius;\n" -"uniform vec3 l_lightcolour;\n" -"uniform vec3 l_lightcolourscale;\n" -"#ifdef PCF\n" -"uniform vec4 l_shadowmapproj; //light projection matrix info\n" -"uniform vec2 l_shadowmapscale; //xy are the texture scale, z is 1, w is the scale.\n" "vec3 ShadowmapCoord(void)\n" "{\n" "#ifdef SPOT\n" @@ -9526,7 +9916,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "#else\n" "#ifdef USE_ARB_SHADOW\n" //with arb_shadow, we can benefit from hardware acclerated pcf, for smoother shadows -"#define dosamp(x,y) shadow2D(s_shadowmap, shadowcoord.xyz + (vec3(x,y,0.0)*l_shadowmapscale.xyx)).r\n" +"#define dosamp(x,y) shadow2D(s_shadowmap, shadowcoord.xyz + (vec3(x,y,0.0)*l_shadowmapscale.xyx))\n" "#else\n" //this will probably be a bit blocky. "#define dosamp(x,y) float(texture2D(s_shadowmap, shadowcoord.xy + (vec2(x,y)*l_shadowmapscale.xy)).r >= shadowcoord.z)\n" diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 9b35afdb..7296f3ab 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -161,7 +161,7 @@ enum SBITS_MISC_DEPTHCLOSERONLY = 0x00080000, //#define SBITS_MISC_BITS 0x000f0000 - SBITS_TRUFORM = 0x00100000, + SBITS_TESSELLATION = 0x00100000, SBITS_AFFINE = 0x00200000, //provided for the backend to hack about with @@ -441,6 +441,7 @@ typedef struct programshared_s { int refs; qboolean nofixedcompat; + qboolean tess; unsigned short numsamplers; //shader system can strip any passes above this unsigned int defaulttextures; //diffuse etc diff --git a/engine/server/server.h b/engine/server/server.h index 74a9ce0c..a59823f4 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -1067,6 +1067,7 @@ void SV_ArgumentOverrides(void); int SV_CalcPing (client_t *cl, qboolean forcecalc); void SV_FullClientUpdate (client_t *client, client_t *to); void SV_GeneratePublicUserInfo(int pext, client_t *cl, char *info, int infolength); +char *SV_PlayerPublicAddress(client_t *cl); int SV_ModelIndex (const char *name); diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index dc9789c8..e4e01ca5 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -1219,7 +1219,7 @@ static void SV_FilterIP_f (void) return; } - if (!NET_StringToAdrMasked(Cmd_Argv(1), &proto.adr, &proto.adrmask)) + if (!NET_StringToAdrMasked(Cmd_Argv(1), true, &proto.adr, &proto.adrmask)) { Con_Printf("invalid address or mask\n"); return; @@ -1368,7 +1368,7 @@ static void SV_Unfilter_f (void) Con_Printf("removing all filtered addresses\n"); all = true; } - else if (!NET_StringToAdrMasked(Cmd_Argv(1), &unbanadr, &unbanmask)) + else if (!NET_StringToAdrMasked(Cmd_Argv(1), true, &unbanadr, &unbanmask)) { Con_Printf("invalid address or mask\n"); return; diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index ff08c9e9..b1991190 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -248,6 +248,8 @@ void SV_Shutdown (void) SV_GibFilterPurge(); + Log_ShutDown(); + NET_Shutdown (); #ifdef PLUGINS @@ -1037,6 +1039,12 @@ CONNECTIONLESS COMMANDS ============================================================================== */ +char *SV_PlayerPublicAddress(client_t *cl) +{ //returns a string containing the client's IP address, as permitted for viewing by other clients. + //if something useful is actually returned, it should be masked. + return "private"; +} + #define STATUS_OLDSTYLE 0 #define STATUS_SERVERINFO 1 #define STATUS_PLAYERS 2 @@ -1165,7 +1173,7 @@ void SVC_GetInfo (char *challenge, int fullstatus) else gamestatus = ""; - COM_ParseOut(com_protocolname.string, protocolname, sizeof(protocolname)); + COM_ParseOut(com_protocolname.string, protocolname, sizeof(protocolname)); //we can only report one, so report the first. resp = response; @@ -1193,7 +1201,8 @@ void SVC_GetInfo (char *challenge, int fullstatus) Info_SetValueForKey(resp, "clients", va("%d", numclients), sizeof(response) - (resp-response)); Info_SetValueForKey(resp, "sv_maxclients", maxclients.string, sizeof(response) - (resp-response)); Info_SetValueForKey(resp, "mapname", Info_ValueForKey(svs.info, "map"), sizeof(response) - (resp-response)); - Info_SetValueForKey(resp, "qcstatus", gamestatus, sizeof(response) - (resp-response)); + if (*gamestatus) + Info_SetValueForKey(resp, "qcstatus", gamestatus, sizeof(response) - (resp-response)); Info_SetValueForKey(resp, "challenge", challenge, sizeof(response) - (resp-response)); resp += strlen(resp); @@ -3770,7 +3779,7 @@ qboolean SVNQ_ConnectionlessPacket(void) MSG_WriteLong (&sb, cl->playercolor); MSG_WriteLong (&sb, cl->old_frags); MSG_WriteLong (&sb, realtime - cl->connection_started); - MSG_WriteString (&sb, ""); /*player's address, leave blank, don't spam that info as it can result in personal attacks exploits*/ + MSG_WriteString (&sb, SV_PlayerPublicAddress(cl)); /*player's address, leave blank, don't spam that info as it can result in personal attacks exploits*/ } *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index ef131e81..ef6a0986 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -5639,7 +5639,7 @@ static void SVNQ_Status_f(void) if (!cl->state) continue; SV_PrintToClient(host_client, PRINT_HIGH, va("#%i\n", i+1)); - SV_PrintToClient(host_client, PRINT_HIGH, va(" %s\n", "WITHHELD")); + SV_PrintToClient(host_client, PRINT_HIGH, va(" %s\n", SV_PlayerPublicAddress(cl))); } } diff --git a/engine/shaders/glsl/defaultskin.glsl b/engine/shaders/glsl/defaultskin.glsl index e9dbc5ed..57f72600 100644 --- a/engine/shaders/glsl/defaultskin.glsl +++ b/engine/shaders/glsl/defaultskin.glsl @@ -1,4 +1,5 @@ -!!ver 100 130 +!!ver 100 150 +!!permu TESS !!permu FULLBRIGHT !!permu UPPERLOWER !!permu FRAMEBLEND @@ -8,6 +9,7 @@ !!cvarf r_glsl_offsetmapping_scale !!cvarf gl_specular !!cvardf gl_affinemodels=0 +!!cvardf r_tessellation=0 #include "sys/defs.h" @@ -16,19 +18,31 @@ //the vertex shader is responsible for calculating lighting values. #if gl_affinemodels==1 && __VERSION__ >= 130 -noperspective -#endif - varying vec2 tc; -varying vec3 light; -#if defined(SPECULAR) || defined(OFFSETMAPPING) -varying vec3 eyevector; +#define affine noperspective +#else +#define affine #endif + + + + #ifdef VERTEX_SHADER #include "sys/skeletal.h" + +affine varying vec2 tc; +varying vec3 light; +#if defined(SPECULAR) || defined(OFFSETMAPPING) +varying vec3 eyevector; +#endif +#ifdef TESS +varying vec3 vertex; +varying vec3 normal; +#endif + void main () { #if defined(SPECULAR)||defined(OFFSETMAPPING) @@ -39,17 +53,120 @@ void main () eyevector.y = dot(eyeminusvertex, t.xyz); eyevector.z = dot(eyeminusvertex, n.xyz); #else - vec3 n; - gl_Position = skeletaltransform_n(n); + vec3 n, s, t, w; + gl_Position = skeletaltransform_wnst(w,n,s,t); #endif + tc = v_texcoord; + float d = dot(n,e_light_dir); if (d < 0.0) //vertex shader. this might get ugly, but I don't really want to make it per vertex. d = 0.0; //this avoids the dark side going below the ambient level. light = e_light_ambient + (dot(n,e_light_dir)*e_light_mul); - tc = v_texcoord; + +#ifdef TESS + normal = n; + vertex = w; +#endif } #endif + + + + + + + + + + +#if defined(TESS_CONTROL_SHADER) +layout(vertices = 3) out; + +in vec3 vertex[]; +out vec3 t_vertex[]; +in vec3 normal[]; +out vec3 t_normal[]; +affine in vec2 tc[]; +affine out vec2 t_tc[]; +in vec3 light[]; +out vec3 t_light[]; +#if defined(SPECULAR) || defined(OFFSETMAPPING) +in vec3 eyevector[]; +out vec3 t_eyevector[]; +#endif +void main() +{ + //the control shader needs to pass stuff through +#define id gl_InvocationID + t_vertex[id] = vertex[id]; + t_normal[id] = normal[id]; + t_tc[id] = tc[id]; + t_light[id] = light[id]; +#if defined(SPECULAR) || defined(OFFSETMAPPING) + t_eyevector[id] = eyevector[id]; +#endif + + gl_TessLevelOuter[0] = float(r_tessellation)+1.0; + gl_TessLevelOuter[1] = float(r_tessellation)+1.0; + gl_TessLevelOuter[2] = float(r_tessellation)+1.0; + gl_TessLevelInner[0] = float(r_tessellation)+1.0; +} +#endif + + + + + + + + + +#if defined(TESS_EVALUATION_SHADER) +layout(triangles) in; + +in vec3 t_vertex[]; +in vec3 t_normal[]; +affine in vec2 t_tc[]; +affine out vec2 tc; +in vec3 t_light[]; +out vec3 light; +#if defined(SPECULAR) || defined(OFFSETMAPPING) +in vec3 t_eyevector[]; +out vec3 eyevector; +#endif + +#define LERP(a) (gl_TessCoord.x*a[0] + gl_TessCoord.y*a[1] + gl_TessCoord.z*a[2]) +void main() +{ +#define factor 1.0 + tc = LERP(t_tc); + vec3 w = LERP(t_vertex); + + vec3 t0 = w - dot(w-t_vertex[0],t_normal[0])*t_normal[0]; + vec3 t1 = w - dot(w-t_vertex[1],t_normal[1])*t_normal[1]; + vec3 t2 = w - dot(w-t_vertex[2],t_normal[2])*t_normal[2]; + w = w*(1.0-factor) + factor*(gl_TessCoord.x*t0+gl_TessCoord.y*t1+gl_TessCoord.z*t2); + + //FIXME: we should be recalcing these here, instead of just lerping them + light = LERP(t_light); +#if defined(SPECULAR) || defined(OFFSETMAPPING) + eyevector = LERP(t_eyevector); +#endif + + gl_Position = m_modelviewprojection * vec4(w,1.0); +} +#endif + + + + + + + + + + #ifdef FRAGMENT_SHADER #include "sys/fog.h" @@ -67,9 +184,10 @@ uniform float cvar_gl_specular; uniform sampler2D s_colourmap; #endif -#if __VERSION__ >= 130 -#define gl_FragColor thecolour -out vec4 thecolour; +affine varying vec2 tc; +varying vec3 light; +#if defined(SPECULAR) || defined(OFFSETMAPPING) +varying vec3 eyevector; #endif diff --git a/engine/shaders/glsl/defaultwall.glsl b/engine/shaders/glsl/defaultwall.glsl index f35ff30c..ca65bbb7 100644 --- a/engine/shaders/glsl/defaultwall.glsl +++ b/engine/shaders/glsl/defaultwall.glsl @@ -1,4 +1,5 @@ -!!ver 100 120 // 130 +!!ver 100 150 +!!permu TESS !!permu DELUXE !!permu FULLBRIGHT !!permu FOG @@ -8,41 +9,42 @@ !!permu REFLECTCUBEMASK !!cvarf r_glsl_offsetmapping_scale !!cvarf gl_specular +!!cvardf r_tessellation=0 #include "sys/defs.h" -#if __VERSION__ >= 130 -#define texture2D texture -#define textureCube texture -#define gl_FragColor gl_FragData[0] -#endif - //this is what normally draws all of your walls, even with rtlights disabled //note that the '286' preset uses drawflat_walls instead. #include "sys/fog.h" -#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) -varying vec3 eyevector; -#endif -#ifdef REFLECTCUBEMASK -varying mat3 invsurface; -#endif +#if !defined(TESS_CONTROL_SHADER) + #if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) + varying vec3 eyevector; + #endif -varying vec2 tc; -#ifdef VERTEXLIT - varying vec4 vc; -#else - #ifdef LIGHTSTYLED - //we could use an offset, but that would still need to be per-surface which would break batches - //fixme: merge attributes? - varying vec2 lm0, lm1, lm2, lm3; + #ifdef REFLECTCUBEMASK + varying mat3 invsurface; + #endif + + varying vec2 tc; + #ifdef VERTEXLIT + varying vec4 vc; #else - varying vec2 lm0; + #ifdef LIGHTSTYLED + //we could use an offset, but that would still need to be per-surface which would break batches + //fixme: merge attributes? + varying vec2 lm0, lm1, lm2, lm3; + #else + varying vec2 lm0; + #endif #endif #endif #ifdef VERTEX_SHADER +#ifdef TESS +varying vec3 vertex, normal; +#endif void main () { #if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) @@ -73,10 +75,151 @@ void main () #endif #endif gl_Position = ftetransform(); + +#ifdef TESS + vertex = v_position; + normal = v_normal; +#endif } #endif +#if defined(TESS_CONTROL_SHADER) +layout(vertices = 3) out; + +in vec3 vertex[]; +out vec3 t_vertex[]; +in vec3 normal[]; +out vec3 t_normal[]; +#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) + in vec3 eyevector[]; + out vec3 t_eyevector[]; +#endif +#ifdef REFLECTCUBEMASK + in mat3 invsurface[]; + out mat3 t_invsurface[]; +#endif +in vec2 tc[]; +out vec2 t_tc[]; +#ifdef VERTEXLIT + in vec4 vc[]; + out vec4 t_vc[]; +#else + in vec2 lm0[]; + out vec2 t_lm0[]; + #ifdef LIGHTSTYLED + in vec2 lm1[], lm2[], lm3[]; + out vec2 t_lm1[], t_lm2[], t_lm3[]; + #endif +#endif +void main() +{ + //the control shader needs to pass stuff through +#define id gl_InvocationID + t_vertex[id] = vertex[id]; + t_normal[id] = normal[id]; + #ifdef REFLECTCUBEMASK + t_invsurface[id] = invsurface[id]; + #endif + t_tc[id] = tc[id]; + #ifdef VERTEXLIT + t_vc[id] = vc[id]; + #else + t_lm0[id] = lm0[id]; + #ifdef LIGHTSTYLED + t_lm1[id] = lm1[id]; + t_lm2[id] = lm2[id]; + t_lm3[id] = lm3[id]; + #endif + #endif + + #if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) + t_eyevector[id] = eyevector[id]; + #endif + + gl_TessLevelOuter[0] = float(r_tessellation)+1.0; + gl_TessLevelOuter[1] = float(r_tessellation)+1.0; + gl_TessLevelOuter[2] = float(r_tessellation)+1.0; + gl_TessLevelInner[0] = float(r_tessellation)+1.0; +} +#endif + + + + + + + + + +#if defined(TESS_EVALUATION_SHADER) +layout(triangles) in; + +in vec3 t_vertex[]; +in vec3 t_normal[]; +#if defined(OFFSETMAPPING) || defined(SPECULAR) || defined(REFLECTCUBEMASK) + in vec3 t_eyevector[]; +#endif +#ifdef REFLECTCUBEMASK + in mat3 t_invsurface[]; +#endif +in vec2 t_tc[]; +#ifdef VERTEXLIT + in vec4 t_vc[]; +#else + #ifdef LIGHTSTYLED + //we could use an offset, but that would still need to be per-surface which would break batches + //fixme: merge attributes? + in vec2 t_lm0[], t_lm1[], t_lm2[], t_lm3[]; + #else + in vec2 t_lm0[]; + #endif +#endif + +#define LERP(a) (gl_TessCoord.x*a[0] + gl_TessCoord.y*a[1] + gl_TessCoord.z*a[2]) +void main() +{ +#define factor 1.0 + tc = LERP(t_tc); + #ifdef VERTEXLIT + vc = LERP(t_vc); + #else + lm0 = LERP(t_lm0); + #ifdef LIGHTSTYLED + lm1 = LERP(t_lm1); + lm2 = LERP(t_lm2); + lm3 = LERP(t_lm3); + #endif + #endif + vec3 w = LERP(t_vertex); + + vec3 t0 = w - dot(w-t_vertex[0],t_normal[0])*t_normal[0]; + vec3 t1 = w - dot(w-t_vertex[1],t_normal[1])*t_normal[1]; + vec3 t2 = w - dot(w-t_vertex[2],t_normal[2])*t_normal[2]; + w = w*(1.0-factor) + factor*(gl_TessCoord.x*t0+gl_TessCoord.y*t1+gl_TessCoord.z*t2); + +#if defined(PCF) || defined(SPOT) || defined(CUBE) + //for texture projections/shadowmapping on dlights + vtexprojcoord = (l_cubematrix*vec4(w.xyz, 1.0)); +#endif + + //FIXME: we should be recalcing these here, instead of just lerping them +#ifdef REFLECTCUBEMASK + invsurface = LERP(t_invsurface); +#endif +#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) + eyevector = LERP(t_eyevector); +#endif + + gl_Position = m_modelviewprojection * vec4(w,1.0); +} +#endif + + + + + + #ifdef FRAGMENT_SHADER //samplers diff --git a/engine/shaders/glsl/depthonly.glsl b/engine/shaders/glsl/depthonly.glsl index 23a4e87e..7a478034 100644 --- a/engine/shaders/glsl/depthonly.glsl +++ b/engine/shaders/glsl/depthonly.glsl @@ -1,5 +1,10 @@ +!!ver 100 150 +!!permu TESS !!permu FRAMEBLEND !!permu SKELETAL +!!cvardf r_tessellation=0 + +#include "sys/defs.h" //standard shader used for drawing shadowmap depth. //also used for masking off portals and other things that want depth and no colour. @@ -8,12 +13,80 @@ #ifdef VERTEX_SHADER #include "sys/skeletal.h" +#ifdef TESS +varying vec3 vertex; +varying vec3 normal; +#endif void main () { +#ifdef TESS + skeletaltransform_n(normal); + vertex = v_position; +#else gl_Position = skeletaltransform(); +#endif } #endif + + +#if defined(TESS_CONTROL_SHADER) +layout(vertices = 3) out; + +in vec3 vertex[]; +out vec3 t_vertex[]; +in vec3 normal[]; +out vec3 t_normal[]; + +void main() +{ + //the control shader needs to pass stuff through +#define id gl_InvocationID + t_vertex[id] = vertex[id]; + t_normal[id] = normal[id]; + gl_TessLevelOuter[0] = float(r_tessellation)+1.0; + gl_TessLevelOuter[1] = float(r_tessellation)+1.0; + gl_TessLevelOuter[2] = float(r_tessellation)+1.0; + gl_TessLevelInner[0] = float(r_tessellation)+1.0; +} +#endif + + + + + + + + + +#if defined(TESS_EVALUATION_SHADER) +layout(triangles) in; + +in vec3 t_vertex[]; +in vec3 t_normal[]; + +#define LERP(a) (gl_TessCoord.x*a[0] + gl_TessCoord.y*a[1] + gl_TessCoord.z*a[2]) +void main() +{ +#define factor 1.0 + vec3 w = LERP(t_vertex); + + vec3 t0 = w - dot(w-t_vertex[0],t_normal[0])*t_normal[0]; + vec3 t1 = w - dot(w-t_vertex[1],t_normal[1])*t_normal[1]; + vec3 t2 = w - dot(w-t_vertex[2],t_normal[2])*t_normal[2]; + w = w*(1.0-factor) + factor*(gl_TessCoord.x*t0+gl_TessCoord.y*t1+gl_TessCoord.z*t2); + + gl_Position = m_modelviewprojection * vec4(w,1.0); +} +#endif + + + + + + + + #ifdef FRAGMENT_SHADER void main () { diff --git a/engine/shaders/glsl/rtlight.glsl b/engine/shaders/glsl/rtlight.glsl index a8eaa146..ceb7b4c3 100644 --- a/engine/shaders/glsl/rtlight.glsl +++ b/engine/shaders/glsl/rtlight.glsl @@ -1,3 +1,5 @@ +!!ver 100 150 +!!permu TESS !!permu BUMP !!permu FRAMEBLEND !!permu SKELETAL @@ -6,7 +8,9 @@ !!permu REFLECTCUBEMASK !!cvarf r_glsl_offsetmapping_scale !!cvardf r_glsl_pcf +!!cvardf r_tessellation=0 +#include "sys/defs.h" #ifndef USE_ARB_SHADOW //fall back on regular samplers if we must @@ -48,31 +52,26 @@ #undef OFFSETMAPPING #endif - -varying vec2 tcbase; -varying vec3 lightvector; -#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) -varying vec3 eyevector; -#endif -#ifdef REFLECTCUBEMASK -varying mat3 invsurface; -uniform mat4 m_model; -#endif -#if defined(PCF) || defined(CUBE) || defined(SPOT) -varying vec4 vtexprojcoord; +#if !defined(TESS_CONTROL_SHADER) + varying vec2 tcbase; + varying vec3 lightvector; + #if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) + varying vec3 eyevector; + #endif + #ifdef REFLECTCUBEMASK + varying mat3 invsurface; + #endif + #if defined(PCF) || defined(CUBE) || defined(SPOT) + varying vec4 vtexprojcoord; + #endif #endif #ifdef VERTEX_SHADER -#if defined(PCF) || defined(CUBE) || defined(SPOT) -uniform mat4 l_cubematrix; +#ifdef TESS +varying vec3 vertex, normal; #endif #include "sys/skeletal.h" -uniform vec3 l_lightposition; -attribute vec2 v_texcoord; -#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) -uniform vec3 e_eyepos; -#endif void main () { vec3 n, s, t, w; @@ -103,57 +102,114 @@ void main () //for texture projections/shadowmapping on dlights vtexprojcoord = (l_cubematrix*vec4(w.xyz, 1.0)); #endif + +#ifdef TESS + vertex = w; + normal = n; +#endif } #endif + + +#if defined(TESS_CONTROL_SHADER) +layout(vertices = 3) out; + +in vec3 vertex[]; +out vec3 t_vertex[]; +in vec3 normal[]; +out vec3 t_normal[]; +in vec2 tcbase[]; +out vec2 t_tcbase[]; +in vec3 lightvector[]; +out vec3 t_lightvector[]; +#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) +in vec3 eyevector[]; +out vec3 t_eyevector[]; +#endif +void main() +{ + //the control shader needs to pass stuff through +#define id gl_InvocationID + t_vertex[id] = vertex[id]; + t_normal[id] = normal[id]; + t_tcbase[id] = tcbase[id]; + t_lightvector[id] = lightvector[id]; +#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) + t_eyevector[id] = eyevector[id]; +#endif + + gl_TessLevelOuter[0] = float(r_tessellation)+1.0; + gl_TessLevelOuter[1] = float(r_tessellation)+1.0; + gl_TessLevelOuter[2] = float(r_tessellation)+1.0; + gl_TessLevelInner[0] = float(r_tessellation)+1.0; +} +#endif + + + + + + + + + +#if defined(TESS_EVALUATION_SHADER) +layout(triangles) in; + +in vec3 t_vertex[]; +in vec3 t_normal[]; +in vec2 t_tcbase[]; +in vec3 t_lightvector[]; +#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) +in vec3 t_eyevector[]; +#endif + +#define LERP(a) (gl_TessCoord.x*a[0] + gl_TessCoord.y*a[1] + gl_TessCoord.z*a[2]) +void main() +{ +#define factor 1.0 + tcbase = LERP(t_tcbase); + vec3 w = LERP(t_vertex); + + vec3 t0 = w - dot(w-t_vertex[0],t_normal[0])*t_normal[0]; + vec3 t1 = w - dot(w-t_vertex[1],t_normal[1])*t_normal[1]; + vec3 t2 = w - dot(w-t_vertex[2],t_normal[2])*t_normal[2]; + w = w*(1.0-factor) + factor*(gl_TessCoord.x*t0+gl_TessCoord.y*t1+gl_TessCoord.z*t2); + +#if defined(PCF) || defined(SPOT) || defined(CUBE) + //for texture projections/shadowmapping on dlights + vtexprojcoord = (l_cubematrix*vec4(w.xyz, 1.0)); +#endif + + //FIXME: we should be recalcing these here, instead of just lerping them + lightvector = LERP(t_lightvector); +#if defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) + eyevector = LERP(t_eyevector); +#endif + + gl_Position = m_modelviewprojection * vec4(w,1.0); +} +#endif + + + + + + + + + + + #ifdef FRAGMENT_SHADER + #include "sys/fog.h" -uniform sampler2D s_diffuse; //diffuse -#if defined(BUMP) || defined(SPECULAR) || defined(OFFSETMAPPING) || defined(REFLECTCUBEMASK) -uniform sampler2D s_normalmap; //normalmap -#endif -#ifdef SPECULAR -uniform sampler2D s_specular; //specular -#endif -#ifdef CUBE -uniform samplerCube s_projectionmap; //projected cubemap -#endif #ifdef PCF -#ifdef CUBESHADOW -uniform samplerCubeShadow s_shadowmap; //shadowmap -#else -#if 0//def GL_ARB_texture_gather -uniform sampler2D s_shadowmap; -#else -uniform sampler2DShadow s_shadowmap; -#endif -#endif -#endif -#ifdef LOWER -uniform sampler2D s_lower; //pants colours -uniform vec3 e_lowercolour; -#endif -#ifdef UPPER -uniform sampler2D s_upper; //shirt colours -uniform vec3 e_uppercolour; -#endif - -#ifdef REFLECTCUBEMASK -uniform sampler2D s_reflectmask; -uniform samplerCube s_reflectcube; -#endif - - -uniform float l_lightradius; -uniform vec3 l_lightcolour; -uniform vec3 l_lightcolourscale; -#ifdef PCF -uniform vec4 l_shadowmapproj; //light projection matrix info -uniform vec2 l_shadowmapscale; //xy are the texture scale, z is 1, w is the scale. vec3 ShadowmapCoord(void) { #ifdef SPOT @@ -222,7 +278,7 @@ float ShadowmapFilter(void) #else #ifdef USE_ARB_SHADOW //with arb_shadow, we can benefit from hardware acclerated pcf, for smoother shadows - #define dosamp(x,y) shadow2D(s_shadowmap, shadowcoord.xyz + (vec3(x,y,0.0)*l_shadowmapscale.xyx)).r + #define dosamp(x,y) shadow2D(s_shadowmap, shadowcoord.xyz + (vec3(x,y,0.0)*l_shadowmapscale.xyx)) #else //this will probably be a bit blocky. #define dosamp(x,y) float(texture2D(s_shadowmap, shadowcoord.xy + (vec2(x,y)*l_shadowmapscale.xy)).r >= shadowcoord.z)