fix Q3BSP-without-Q2BSP bug.

reworked deferred rendering to support specular. mrt can be reconfigured by TCs if desired.
reworked q3bsp deluxemap code (so it no longer bugs out).
fixed a few warnings.
updated fteqcc to try to cope with xonotic. still not working (xonotic fails from bound checks).
reworked shader conditionals to support elif. added some directives from QF(aka: warsow)

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5158 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2017-10-31 22:52:58 +00:00
parent b8d0718b5c
commit 52f0f117ab
53 changed files with 2061 additions and 1690 deletions

View file

@ -537,10 +537,9 @@ else
#really we want dumpmachine's more specific cpu arch included here, so lets hope that idiot burns for all eternity. or something equally melodramatic.
ARCH:=$(shell $(CC) -print-multiarch)
ifneq ($(words $(ARCH)),1)
foo:=$(shell echo falling back on dumpmachine 1>&2 )
ARCH:=$(shell $(CC) -dumpmachine)
endif
foo:=$(shell echo ARCH is $(ARCH) 1>&2 )
#foo:=$(shell echo ARCH is $(ARCH) 1>&2 )
endif
ARCHLIBS=$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)

View file

@ -1180,8 +1180,6 @@ float CL_FilterTime (double time, float wantfps, float limit, qboolean ignoreser
return time - (1000 / fps);
}
qboolean allowindepphys;
typedef struct clcmdbuf_s {
struct clcmdbuf_s *next;
int len;
@ -1211,8 +1209,7 @@ void VARGS CL_SendClientCommand(qboolean reliable, char *format, ...)
}
#endif
oldallow = allowindepphys;
CL_AllowIndependantSendCmd(false);
oldallow = CL_AllowIndependantSendCmd(false);
buf = Z_Malloc(sizeof(*buf)+strlen(string));
strcpy(buf->command, string);
@ -1289,10 +1286,12 @@ qboolean runningindepphys;
void *indeplock;
void *indepthread;
void CL_AllowIndependantSendCmd(qboolean allow)
qboolean allowindepphys;
qboolean CL_AllowIndependantSendCmd(qboolean allow)
{
qboolean ret = allowindepphys;
if (!runningindepphys)
return;
return ret;
if (allowindepphys != allow && runningindepphys)
{
@ -1302,6 +1301,7 @@ void CL_AllowIndependantSendCmd(qboolean allow)
Sys_LockMutex(indeplock);
allowindepphys = allow;
}
return ret;
}
int CL_IndepPhysicsThread(void *param)
@ -1362,8 +1362,9 @@ void CL_UseIndepPhysics(qboolean allow)
}
}
#else
void CL_AllowIndependantSendCmd(qboolean allow)
qboolean CL_AllowIndependantSendCmd(qboolean allow)
{
return false;
}
void CL_UseIndepPhysics(qboolean allow)
{

View file

@ -5429,7 +5429,7 @@ double Host_Frame (double time)
}
else
#endif
if ((cl_netfps.value>0 || cls.demoplayback || cl_threadedphysics.ival))
if ((cl_netfps.value>0 || cls.demoplayback || runningindepphys))
{ //limit the fps freely, and expect the netfps to cope.
maxfpsignoreserver = true;
maxfps = cl_maxfps.ival;
@ -5516,7 +5516,7 @@ double Host_Frame (double time)
RSpeedRemark();
CL_UseIndepPhysics(!!cl_threadedphysics.ival);
CL_UseIndepPhysics(cls.state != ca_disconnected && !!cl_threadedphysics.ival); //starts/stops the input frame thread.
cl.do_lerp_players = cl_lerp_players.ival || (cls.demoplayback==DPB_MVD || cls.demoplayback == DPB_EZTV) || (cls.demoplayback && !cl_nolerp.ival && !cls.timedemo);
CL_AllowIndependantSendCmd(false);
@ -6167,6 +6167,8 @@ void Host_Shutdown(void)
return;
host_initialized = false;
CL_UseIndepPhysics(false);
#ifdef WEBCLIENT
HTTP_CL_Terminate();
#endif

View file

@ -1182,12 +1182,13 @@ void Key_GetBindMap(int *bindmaps);
void Key_SetBindMap(int *bindmaps);
void CL_UseIndepPhysics(qboolean allow);
extern qboolean runningindepphys;
qboolean CL_AllowIndependantSendCmd(qboolean allow); //returns previous state.
void CL_FlushClientCommands(void);
void VARGS CL_SendClientCommand(qboolean reliable, char *format, ...) LIKEPRINTF(2);
float CL_FilterTime (double time, float wantfps, float limit, qboolean ignoreserver);
int CL_RemoveClientCommands(char *command);
void CL_AllowIndependantSendCmd(qboolean allow);
//
// cl_demo.c

View file

@ -19,11 +19,11 @@ cvar_t r_dodgypcxfiles = CVARD("r_dodgypcxfiles", "0", "When enabled, this will
cvar_t r_dodgymiptex = CVARD("r_dodgymiptex", "1", "When enabled, this will force regeneration of mipmaps, discarding mips1-4 like glquake did. This may eg solve fullbright issues with some maps, but may reduce distant detail levels.");
char *r_defaultimageextensions =
#ifdef IMAGEFMT_KTX
"ktx " //compressed or something
#endif
#ifdef IMAGEFMT_DDS
"dds " //compressed or something
#endif
#ifdef IMAGEFMT_KTX
"ktx " //compressed or something. not to be confused with the qw mod by the same name. GL requires that etc2 compression is supported by modern drivers, but not necessarily the hardware. as such, dds with its s3tc bias should always come first (as the patents mean that drivers are much less likely to advertise it when they don't support it properly).
#endif
"tga" //fairly fast to load
#if defined(AVAIL_PNGLIB) || defined(FTE_TARGET_WEB)
@ -2659,40 +2659,40 @@ static qboolean Image_ReadKTXFile(texid_t tex, unsigned int flags, char *fname,
switch(header->glinternalformat)
{
case GL_ETC1_RGB8_OES:
case 0x8D64/*GL_ETC1_RGB8_OES*/:
encoding = PTI_ETC1_RGB8;
break;
case GL_COMPRESSED_RGB8_ETC2:
case GL_COMPRESSED_SRGB8_ETC2:
case 0x9274/*GL_COMPRESSED_RGB8_ETC2*/:
case 0x9275/*GL_COMPRESSED_SRGB8_ETC2*/:
encoding = PTI_ETC2_RGB8;
break;
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case 0x9276/*GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2*/:
case 0x9277/*GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2*/:
encoding = PTI_ETC2_RGB8A1;
break;
case GL_COMPRESSED_RGBA8_ETC2_EAC:
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
case 0x9278/*GL_COMPRESSED_RGBA8_ETC2_EAC*/:
case 0x9279/*GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC*/:
encoding = PTI_ETC2_RGB8A8;
break;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case 0x83F0/*GL_COMPRESSED_RGB_S3TC_DXT1_EXT*/:
encoding = PTI_S3RGB1;
break;
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case 0x83F1/*GL_COMPRESSED_RGBA_S3TC_DXT1_EXT*/:
encoding = PTI_S3RGBA1;
break;
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
case 0x83F2/*GL_COMPRESSED_RGBA_S3TC_DXT3_EXT*/:
encoding = PTI_S3RGBA3;
break;
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
case 0x83F3/*GL_COMPRESSED_RGBA_S3TC_DXT5_EXT*/:
encoding = PTI_S3RGBA5;
break;
case GL_BGRA_EXT:
case 0x80E1/*GL_BGRA_EXT*/:
encoding = PTI_BGRA8;
break;
case GL_RGBA:
case 0x1908/*GL_RGBA*/:
encoding = PTI_RGBA8;
break;
case GL_SRGB8_ALPHA8_EXT:
case 0x8C43/*GL_SRGB8_ALPHA8_EXT*/:
encoding = PTI_RGBA8_SRGB;
break;
case 0x8045/*GL_LUMINANCE8_ALPHA8*/:
@ -5711,14 +5711,14 @@ void Image_Init(void)
memset(imagetablebuckets, 0, sizeof(imagetablebuckets));
Hash_InitTable(&imagetable, sizeof(imagetablebuckets)/sizeof(imagetablebuckets[0]), imagetablebuckets);
Cmd_AddCommandD("image_list", Image_List_f, "Prints out a list of the currently-known textures.");
Cmd_AddCommandD("r_image_list", Image_List_f, "Prints out a list of the currently-known textures.");
}
//destroys all textures
void Image_Shutdown(void)
{
image_t *tex;
int i = 0, j = 0;
Cmd_RemoveCommand("image_list");
Cmd_RemoveCommand("r_image_list");
while (imagelist)
{
tex = imagelist;

View file

@ -557,10 +557,14 @@ void IN_Commands(void)
//down: x= +9.8
//left: y= -9.8
//up: z= +9.8
#ifdef CSQC_DAT
CSQC_Accelerometer(ev->accel.x, ev->accel.y, ev->accel.z);
#endif
break;
case IEV_GYROSCOPE:
#ifdef CSQC_DAT
CSQC_Gyroscope(ev->gyro.pitch * 180.0/M_PI, ev->gyro.yaw * 180.0/M_PI, ev->gyro.roll * 180.0/M_PI);
#endif
break;
}
events_used++;

View file

@ -867,18 +867,22 @@ void Key_DefaultLinkClicked(console_t *con, char *text, char *info)
Cbuf_AddText(va("\nplaydemo \"%s\"\n", c), RESTRICT_LOCAL);
return;
}
#ifndef CLIENTONLY
c = Info_ValueForKey(info, "map");
if (*c && !strchr(c, ';') && !strchr(c, '\n'))
{
Cbuf_AddText(va("\nmap \"%s\"\n", c), RESTRICT_LOCAL);
return;
}
#endif
#ifndef NOBUILTINMENUS
c = Info_ValueForKey(info, "modelviewer");
if (*c && !strchr(c, ';') && !strchr(c, '\n'))
{
Cbuf_AddText(va("\nmodelviewer \"%s\"\n", c), RESTRICT_LOCAL);
return;
}
#endif
c = Info_ValueForKey(info, "type");
if (*c)
{
@ -909,24 +913,28 @@ void Key_DefaultLinkClicked(console_t *con, char *text, char *info)
Cbuf_AddText(va("\necho Contents of %s:\ndir \"%s\"\n", c, c), RESTRICT_LOCAL);
return;
}
#ifdef TEXTEDITOR
c = Info_ValueForKey(info, "edit");
if (*c && !strchr(c, ';') && !strchr(c, '\n'))
{
Cbuf_AddText(va("\nedit \"%s\"\n", c), RESTRICT_LOCAL);
return;
}
#endif
c = Info_ValueForKey(info, "impulse");
if (*c && !strchr(c, ';') && !strchr(c, '\n'))
{
Cbuf_AddText(va("\nimpulse %s\n", c), RESTRICT_LOCAL);
return;
}
#ifdef HAVE_MEDIA_DECODER
c = Info_ValueForKey(info, "film");
if (*c && !strchr(c, ';') && !strchr(c, '\n'))
{
Cbuf_AddText(va("\nplayfilm \"%s\"\n", c), RESTRICT_LOCAL);
return;
}
#endif
c = Info_ValueForKey(info, "desc");
if (*c)
{

View file

@ -558,7 +558,7 @@ void CD_f (void)
Con_Printf(" %u -> %s\n", n, cdremap[n].fname);
return;
}
for (n = 1; n <= ret; n++)
for (n = 1; n <= ret && n < REMAPPED_TRACKS; n++)
Q_strncpyz(cdremap[n].fname, Cmd_Argv (n+1), sizeof(cdremap[n].fname));
return;
}

View file

@ -1620,7 +1620,8 @@ static const char *maplist_q2[] =
"city2",
"city3",
"boss1",
"boss2"
"boss2",
NULL
};
static const char *mapoptions_q2[] =
{
@ -1692,7 +1693,7 @@ qboolean M_Apply_SP_Cheats (union menuoption_s *op,struct menu_s *menu,int key)
}
#ifndef CLIENTONLY
if ((unsigned int)info->mapcombo->selectedoption >= sizeof(maplist_q1)/sizeof(maplist_q1[0]))
if ((unsigned int)info->mapcombo->selectedoption < countof(maplist_q1)-1)
Cbuf_AddText(va("map %s\n", maplist_q1[info->mapcombo->selectedoption]), RESTRICT_LOCAL);
#endif
@ -1733,7 +1734,7 @@ void M_Menu_Singleplayer_Cheats_Quake (void)
else
currentskill = skill.value;
for (currentmap = sizeof(maplist_q1)/sizeof(maplist_q1[0]) - 1; currentmap > 0; currentmap--)
for (currentmap = countof(maplist_q1); currentmap --> 0; )
if (!strcmp(host_mapname.string, maplist_q1[currentmap]))
break;
/*anything that doesn't match will end up with 0*/
@ -1807,7 +1808,7 @@ qboolean M_Apply_SP_Cheats_Q2 (union menuoption_s *op,struct menu_s *menu,int ke
break;
}
if ((unsigned int)info->mapcombo->selectedoption >= sizeof(maplist_q2)/sizeof(maplist_q2[0]))
if ((unsigned int)info->mapcombo->selectedoption < countof(maplist_q2)-1)
Cbuf_AddText(va("map %s\n", maplist_q2[info->mapcombo->selectedoption]), RESTRICT_LOCAL);
M_RemoveMenu(menu);
@ -1847,7 +1848,7 @@ void M_Menu_Singleplayer_Cheats_Quake2 (void)
else
currentskill = skill.value;
for (currentmap = sizeof(maplist_q2)/sizeof(maplist_q2[0]) - 1; currentmap > 0; currentmap--)
for (currentmap = countof(maplist_q2); currentmap --> 0; )
if (!strcmp(host_mapname.string, maplist_q2[currentmap]))
break;
/*anything that doesn't match will end up with 0*/

View file

@ -1437,7 +1437,10 @@ void CLMaster_AddMaster_Worker_Resolve(void *ctx, void *data, size_t a, size_t b
}
//add the main ip address
if (found)
work->adr = adrs[0];
else
memset(&work->adr, 0, sizeof(work->adr));
COM_AddWork(WG_MAIN, CLMaster_AddMaster_Worker_Resolved, NULL, work, a, b);
//add dupes too (eg: ipv4+ipv6)

View file

@ -2347,7 +2347,7 @@ void Surf_SetupFrame(void)
r_viewcluster = -1;
r_viewcluster2 = -1;
}
#ifdef Q2BSPS
#if defined(Q2BSPS) || defined(Q3BSPS)
else if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3)
{
leaf = Mod_PointInLeaf (cl.worldmodel, pvsorg);
@ -3473,7 +3473,7 @@ void Surf_BuildModelLightmaps (model_t *m)
if (m->fromgame == fg_quake3)
{
int j;
unsigned char *src;
unsigned char *src, *stop;
unsigned char *dst;
@ -3505,6 +3505,9 @@ void Surf_BuildModelLightmaps (model_t *m)
dst = lightmap[newfirst+i]->lightmaps;
src = m->lightdata + i*m->lightmaps.width*m->lightmaps.height*3;
stop = m->lightdata + (i+1)*m->lightmaps.width*m->lightmaps.height*3;
if (stop-m->lightdata > m->lightdatasize)
stop = m->lightdata + m->lightdatasize;
if (m->lightdata)
{
switch(lightmap_fmt)
@ -3513,7 +3516,7 @@ void Surf_BuildModelLightmaps (model_t *m)
Sys_Error("Bad lightmap_fmt\n");
break;
case TF_BGRA32:
for (j = min((m->lightdatasize-i*m->lightmaps.width*m->lightmaps.height*3)/3,m->lightmaps.width*m->lightmaps.height); j > 0; j--, dst += 4, src += 3)
for (; src < stop; dst += 4, src += 3)
{
dst[0] = src[2];
dst[1] = src[1];
@ -3522,7 +3525,7 @@ void Surf_BuildModelLightmaps (model_t *m)
}
break;
/*case TF_RGBA32:
for (j = min((m->lightdatasize-i*m->lightmaps.width*m->lightmaps.height*3)/3,m->lightmaps.width*m->lightmaps.height); j > 0; j--, dst += 4, src += 3)
for (; src < stop; dst += 4, src += 3)
{
dst[0] = src[0];
dst[1] = src[1];
@ -3531,7 +3534,7 @@ void Surf_BuildModelLightmaps (model_t *m)
}
break;
case TF_BGR24:
for (j = 0; j < m->lightmaps.width*m->lightmaps.height; j++, dst += 3, src += 3)
for (; src < stop; dst += 3, src += 3)
{
dst[0] = src[2];
dst[1] = src[1];
@ -3539,7 +3542,7 @@ void Surf_BuildModelLightmaps (model_t *m)
}
break;*/
case TF_RGB24:
for (j = 0; j < m->lightmaps.width*m->lightmaps.height; j++, dst += 3, src += 3)
for (; src < stop; dst += 3, src += 3)
{
dst[0] = src[0];
dst[1] = src[1];

View file

@ -320,8 +320,8 @@ const static GUID QKSDATAFORMAT_SUBTYPE_PCM = {0x00000001,0x0000,0x0010, {0x80
const static GUID QKSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003,0x0000,0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
#ifdef _IKsPropertySet_
const static GUID CLSID_EAXDIRECTSOUND = {0x4ff53b81, 0x1ce0, 0x11d3,
{0xaa, 0xb8, 0x0, 0xa0, 0xc9, 0x59, 0x49, 0xd5}};
//const static GUID CLSID_EAXDIRECTSOUND = {0x4ff53b81, 0x1ce0, 0x11d3,
//{0xaa, 0xb8, 0x0, 0xa0, 0xc9, 0x59, 0x49, 0xd5}};
const static GUID DSPROPSETID_EAX20_LISTENERPROPERTIES = {0x306a6a8, 0xb224, 0x11d2,
{0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22}};
@ -393,11 +393,11 @@ typedef enum
DSPROPERTY_EAXLISTENER_FLAGS
} DSPROPERTY_EAX_LISTENERPROPERTY;
const static GUID DSPROPSETID_EAX20_BUFFERPROPERTIES ={
/*const static GUID DSPROPSETID_EAX20_BUFFERPROPERTIES ={
0x306a6a7,
0xb224,
0x11d2,
{0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22}};
{0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22}};*/
const static GUID CLSID_EAXDirectSound ={
0x4ff53b81,
@ -685,7 +685,7 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
usereverb = !!snd_eax.ival;
//EAX attempt
#if _MSC_VER > 1200
#if 1//_MSC_VER > 1200
#ifdef _IKsPropertySet_
dh->pDS = NULL;
if (usereverb)
@ -961,7 +961,7 @@ static int DSOUND_InitCard_Internal (soundcardinfo_t *sc, char *cardname)
sc->GetDMAPos = DSOUND_GetDMAPos;
sc->Restore = DSOUND_Restore;
#if _MSC_VER > 1200
#if 1//_MSC_VER > 1200
#ifdef _IKsPropertySet_
//attempt at eax support
if (usereverb == 2)

View file

@ -218,7 +218,7 @@ SNDDM_InitWav
Crappy windows multimedia base
==================
*/
qboolean WAV_InitCard (soundcardinfo_t *sc, const char *cardname)
qboolean QDECL WAV_InitCard (soundcardinfo_t *sc, const char *cardname)
{
WAVEFORMATEX format;
int i;

View file

@ -82,7 +82,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define STRINGIFY(s) STRINGIFY2(s)
#ifdef CONFIG_FILE_NAME
//yup, C89 allows this.
//yup, C89 allows this (doesn't like C's token concat though).
#include STRINGIFY(CONFIG_FILE_NAME)
#elif defined(HAVE_CONFIG_H) //if it was configured properly, then we have a more correct list of features we want to use.
#include "config.h"
@ -220,7 +220,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MD1MODELS //quake ain't much use without this
#define MD3MODELS //we DO want to use quake3 alias models. This might be a minimal build, but we still want this.
#define PLUGINS
#define NOQCDESCRIPTIONS //trim space from no fteextensions.qc info
#define NOQCDESCRIPTIONS 2 //trim space from no fteextensions.qc info
#define PSET_CLASSIC

View file

@ -762,7 +762,7 @@ static int QDECL COM_Dir_List(const char *name, qofs_t size, time_t mtime, void
if (*name && name[strlen(name)-1] == '/')
{
colour = "^7"; //superseeded
Q_snprintfz(link, sizeof(link), "\\dir\\%s*", name);
Q_snprintfz(link, sizeof(link), "\\tip\\Scan Sub-Directory\\dir\\%s*", name);
}
else if (!FS_FLocateFile(name, FSLF_IFFOUND, &loc))
{
@ -775,17 +775,18 @@ static int QDECL COM_Dir_List(const char *name, qofs_t size, time_t mtime, void
COM_FileExtension(name, link, sizeof(link));
if ((!Q_strcasecmp(link, "bsp") || !Q_strcasecmp(link, "map") || !Q_strcasecmp(link, "hmp")) && !strncmp(name, "maps/", 5) && strncmp(name, "maps/b_", 7))
{
Q_snprintfz(link, sizeof(link), "\\map\\%s", name);
Q_snprintfz(link, sizeof(link), "\\tip\\Change Map\\map\\%s", name+5);
colour = "^4"; //disconnects
}
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, "md5anim"))
Q_snprintfz(link, sizeof(link), "\\modelviewer\\%s", name);
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")
|| !Q_strcasecmp(link, "cfg") || !Q_strcasecmp(link, "rc")
|| !Q_strcasecmp(link, "txt") || !Q_strcasecmp(link, "log")
|| !Q_strcasecmp(link, "ent") || !Q_strcasecmp(link, "rtlights")
|| !Q_strcasecmp(link, "glsl") || !Q_strcasecmp(link, "hlsl")
|| !Q_strcasecmp(link, "shader") || !Q_strcasecmp(link, "framegroups"))
Q_snprintfz(link, sizeof(link), "\\edit\\%s", name);
Q_snprintfz(link, sizeof(link), "\\tip\\Open in Text Editor\\edit\\%s", name);
else if (!Q_strcasecmp(link, "tga") || !Q_strcasecmp(link, "png") || !Q_strcasecmp(link, "jpg") || !Q_strcasecmp(link, "jpeg") || !Q_strcasecmp(link, "lmp") || !Q_strcasecmp(link, "pcx") || !Q_strcasecmp(link, "bmp") || !Q_strcasecmp(link, "dds"))
{
//FIXME: image replacements are getting in the way here.
@ -794,11 +795,11 @@ static int QDECL COM_Dir_List(const char *name, qofs_t size, time_t mtime, void
}
else if (!Q_strcasecmp(link, "qwd") || !Q_strcasecmp(link, "dem") || !Q_strcasecmp(link, "mvd") || !Q_strcasecmp(link, "dm2"))
{
Q_snprintfz(link, sizeof(link), "\\demo\\%s", name);
Q_snprintfz(link, sizeof(link), "\\tip\\Play Demo\\demo\\%s", name);
colour = "^4"; //disconnects
}
else if (!Q_strcasecmp(link, "roq") || !Q_strcasecmp(link, "cin") || !Q_strcasecmp(link, "avi") || !Q_strcasecmp(link, "mp4") || !Q_strcasecmp(link, "mkv"))
Q_snprintfz(link, sizeof(link), "\\film\\%s", name);
Q_snprintfz(link, sizeof(link), "\\tip\\Play Film\\film\\%s", name);
else
{
colour = "^3"; //nothing

View file

@ -3018,10 +3018,6 @@ static qboolean CModRBSP_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l)
out->plane = pl;
facetype = LittleLong(in->facetype);
out->texinfo = mod->texinfo + LittleLong(in->shadernum);
if (facetype == MST_FLARE)
out->texinfo = mod->texinfo + mod->numtexinfo*2;
else if (facetype == MST_TRIANGLE_SOUP || r_vertexlight.value)
out->texinfo += mod->numtexinfo; //soup/vertex light uses a different version of the same shader (with all the lightmaps collapsed)
for (j = 0; j < 4 && j < MAXRLIGHTMAPS; j++)
{
out->lightmaptexturenums[j] = LittleLong(in->lightmapnum[j]);
@ -3032,6 +3028,11 @@ static qboolean CModRBSP_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l)
if (mod->lightmaps.count < out->lightmaptexturenums[j]+1)
mod->lightmaps.count = out->lightmaptexturenums[j]+1;
}
if (facetype == MST_FLARE)
out->texinfo = mod->texinfo + mod->numtexinfo*2;
else if (out->lightmaptexturenums[0]<0 || r_vertexlight.value)
out->texinfo += mod->numtexinfo; //soup/vertex light uses a different version of the same shader (with all the lightmaps collapsed)
out->lmshift = LMSHIFT_DEFAULT;
out->extents[0] = (LittleLong(in->lightmap_width)-1)<<out->lmshift;
out->extents[1] = (LittleLong(in->lightmap_height)-1)<<out->lmshift;
@ -3497,14 +3498,62 @@ static void CModQ3_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l)
loadmodel->engineflags |= MDLF_NEEDOVERBRIGHT;
loadmodel->engineflags |= MDLF_RGBLIGHTING;
loadmodel->lightdata = out = ZG_Malloc(&loadmodel->memgroup, samples);
if (loadmodel->lightmaps.deluxemapping)
maps /= 2;
{
int limit = min(sh_config.texture_maxsize / loadmodel->lightmaps.height, 16);//mod_mergeq3lightmaps.ival);
loadmodel->lightmaps.merge = 1;
while (loadmodel->lightmaps.merge*2 <= limit && loadmodel->lightmaps.merge < maps)
loadmodel->lightmaps.merge *= 2;
}
//q3bsp itself does not support deluxemapping.
//the way it works is by interleaving the data in lightmap+deluxemap pairs.
//the surface data makes no references to the deluxemap maps, they're implied by lightmap+1
//if no surface references an odd lightmap index then we know we have deluxemaps... assuming there are at least two lightmaps.
//q3map2 likes generating null lightmaps, so beware false positives.
//note that external lighting makes this even more fun.
//if we have deluxemapping data then we split it here. beware externals.
if (loadmodel->lightmaps.deluxemapping)
{
m = loadmodel->lightmaps.merge;
while (m < maps)
m += loadmodel->lightmaps.merge;
loadmodel->lightdata = ZG_Malloc(&loadmodel->memgroup, mapsize*m*2);
loadmodel->lightdatasize = mapsize*m*2;
}
else
{
loadmodel->lightdatasize = samples;
loadmodel->lightdata = ZG_Malloc(&loadmodel->memgroup, samples);
}
if (!loadmodel->lightdata)
return;
//be careful here, q3bsp deluxemapping is done using interleaving. we want to unoverbright ONLY lightmaps and not deluxemaps.
for (m = 0; m < maps; m++)
{
if (loadmodel->lightmaps.deluxemapping && (m & 1))
out = loadmodel->lightdata;
//figure out which merged lightmap we're putting it into
out += (m/loadmodel->lightmaps.merge)*loadmodel->lightmaps.merge*mapsize * (loadmodel->lightmaps.deluxemapping?2:1);
//and the submap
out += (m%loadmodel->lightmaps.merge)*mapsize;
for(s = 0; s < mapsize; s++)
out[s] = lmgamma[*in++];
if (r_lightmap_saturation.value != 1.0f)
SaturateR8G8B8(out, mapsize, r_lightmap_saturation.value);
if (loadmodel->lightmaps.deluxemapping)
{
out+= loadmodel->lightmaps.merge*mapsize;
//no gamma for deluxemap
for(s = 0; s < mapsize; s+=3)
{
@ -3514,24 +3563,21 @@ static void CModQ3_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l)
in += 3;
}
}
else
{
for(s = 0; s < mapsize; s++)
{
*out++ = lmgamma[*in++];
}
for (; m%loadmodel->lightmaps.merge; m++)
{
out = loadmodel->lightdata;
//figure out which merged lightmap we're putting it into
out += (m/loadmodel->lightmaps.merge)*loadmodel->lightmaps.merge*mapsize * (loadmodel->lightmaps.deluxemapping?2:1);
//and the submap
out += (m%loadmodel->lightmaps.merge)*mapsize;
if (r_lightmap_saturation.value != 1.0f)
SaturateR8G8B8(out - mapsize, mapsize, r_lightmap_saturation.value);
}
}
if (loadmodel->lightdata)
for(s = 0; s < mapsize; s+=3)
{
int limit = min(sh_config.texture_maxsize / loadmodel->lightmaps.height, 16);//mod_mergeq3lightmaps.ival);
loadmodel->lightmaps.merge = 1;
while (loadmodel->lightmaps.merge*2 <= limit)
loadmodel->lightmaps.merge *= 2;
out[s+0] = 0;
out[s+1] = 255;
out[s+2] = 0;
}
}
}
@ -4077,6 +4123,9 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole
else
#endif
noerrors = noerrors && CModQ3_LoadFaces (mod, mod_base, &header.lumps[Q3LUMP_SURFACES]);
if (noerrors)
Mod_LoadEntities (mod, mod_base, &header.lumps[Q3LUMP_ENTITIES]);
#ifndef SERVERONLY
if (qrenderer != QR_NONE)
{
@ -4110,7 +4159,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole
facesize = sizeof(q3dface_t);
mod->lightmaps.surfstyles = 1;
}
if (noerrors && mod->fromgame == fg_quake3)
if (noerrors)
{
i = header.lumps[Q3LUMP_LIGHTMAPS].filelen / (mod->lightmaps.width*mod->lightmaps.height*3);
mod->lightmaps.deluxemapping = !(i&1);
@ -4122,6 +4171,28 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole
if (mod->surfaces[i].lightmaptexturenums[0] >= 0 && (mod->surfaces[i].lightmaptexturenums[0] & 1))
mod->lightmaps.deluxemapping = false;
}
{
char deluxeMaps[64], *key;
key = (char*)Mod_ParseWorldspawnKey(mod, "deluxeMaps", deluxeMaps, sizeof(deluxeMaps));
if (*key)
{
switch(atoi(key))
{
case 0:
mod->lightmaps.deluxemapping = false;
break;
case 1:
// mod->lightmaps.deluxemapping = true;
mod->lightmaps.deluxemapping_modelspace = true;
break;
case 2:
// mod->lightmaps.deluxemapping = true;
mod->lightmaps.deluxemapping_modelspace = false;
break;
}
}
}
}
if (noerrors)
@ -4132,8 +4203,6 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole
noerrors = noerrors && CModQ3_LoadNodes (mod, mod_base, &header.lumps[Q3LUMP_NODES]);
noerrors = noerrors && CModQ3_LoadSubmodels (mod, mod_base, &header.lumps[Q3LUMP_MODELS]);
noerrors = noerrors && CModQ3_LoadVisibility (mod, mod_base, &header.lumps[Q3LUMP_VISIBILITY]);
if (noerrors)
Mod_LoadEntities (mod, mod_base, &header.lumps[Q3LUMP_ENTITIES]);
if (!noerrors)
{
@ -4160,28 +4229,6 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole
mod->funcs.NativeContents = CM_NativeContents;
#ifndef SERVERONLY
{
char deluxeMaps[64], *key;
key = (char*)Mod_ParseWorldspawnKey(mod, "deluxeMaps", deluxeMaps, sizeof(deluxeMaps));
if (*key)
{
switch(atoi(key))
{
case 0:
mod->lightmaps.deluxemapping = false;
break;
case 1:
// mod->lightmaps.deluxemapping = true;
mod->lightmaps.deluxemapping_modelspace = true;
break;
case 2:
// mod->lightmaps.deluxemapping = true;
mod->lightmaps.deluxemapping_modelspace = false;
break;
}
}
}
//light grid info
if (mod->lightgrid)
{
@ -6502,7 +6549,7 @@ int CM_WriteAreaBits (model_t *mod, qbyte *buffer, int area, qboolean merge)
bytes = (prv->numareas+7)>>3;
if (map_noareas.value)
if (map_noareas.value || (area < 0 && !merge))
{ // for debugging, send everything
if (!merge)
memset (buffer, 255, bytes);

View file

@ -2657,6 +2657,7 @@ int FTENET_GetLocalAddress(int port, qboolean ipx, qboolean ipv4, qboolean ipv6,
struct sockaddr_in6 from;
from.sin6_family = AF_INET6;
from.sin6_port = port;
from.sin6_scope_id = 0;
memcpy(&from.sin6_addr, h->h_addr_list[b], sizeof(((struct sockaddr_in6*)&from)->sin6_addr));
SockadrToNetadr((struct sockaddr_qstorage*)&from, addresses);
*adrflags++ = 0;

View file

@ -1326,27 +1326,39 @@ qintptr_t VARGS Plug_memmove(void *offset, quintptr_t mask, const qintptr_t *arg
qintptr_t VARGS Plug_sqrt(void *offset, quintptr_t mask, const qintptr_t *arg)
{
int ret;
VM_FLOAT(ret) = sqrt(VM_FLOAT(arg[0]));
return ret;
union {
qintptr_t i;
float f;
} ret = {0};
ret.f = sqrt(VM_FLOAT(arg[0]));
return ret.i;
}
qintptr_t VARGS Plug_sin(void *offset, quintptr_t mask, const qintptr_t *arg)
{
int ret;
VM_FLOAT(ret) = sin(VM_FLOAT(arg[0]));
return ret;
union {
qintptr_t i;
float f;
} ret = {0};
ret.f = sin(VM_FLOAT(arg[0]));
return ret.i;
}
qintptr_t VARGS Plug_cos(void *offset, quintptr_t mask, const qintptr_t *arg)
{
int ret;
VM_FLOAT(ret) = cos(VM_FLOAT(arg[0]));
return ret;
union {
qintptr_t i;
float f;
} ret = {0};
ret.f = cos(VM_FLOAT(arg[0]));
return ret.i;
}
qintptr_t VARGS Plug_atan2(void *offset, quintptr_t mask, const qintptr_t *arg)
{
int ret;
VM_FLOAT(ret) = atan2(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]));
return ret;
union {
qintptr_t i;
float f;
} ret = {0};
ret.f = atan2(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]));
return ret.i;
}
void Plug_Net_Close_Internal(int handle)

View file

@ -1188,7 +1188,7 @@ void QCBUILTIN PF_touchtriggers(pubprogfuncs_t *prinst, struct globalvars_s *pr_
//entity(string field, float match) findchainflags = #450
//chained search for float, int, and entity reference fields
void PF_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
void QCBUILTIN PF_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int i, ff, cf;
int s;
@ -1219,7 +1219,7 @@ void PF_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
}
//entity(string field, float match) findchainfloat = #403
void PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int i, ff, cf;
float s;
@ -1251,7 +1251,7 @@ void PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
//entity(string field, string match) findchain = #402
//chained search for strings in entity fields
void PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
void QCBUILTIN PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int i, ff, cf;
const char *s;

View file

@ -151,8 +151,8 @@ void QCBUILTIN PF_vectoyaw (pubprogfuncs_t *prinst, struct globalvars_s *pr_glob
void QCBUILTIN PF_vectoangles (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_rotatevectorsbyangles (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_rotatevectorsbymatrix (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_coredump (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_traceon (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_traceoff (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -302,7 +302,7 @@ void QCBUILTIN PF_cvars_haveunsaved (pubprogfuncs_t *prinst, struct globalvars_s
void QCBUILTIN PF_cvar_set (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_cvar_setf (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_ArgC (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_randomvec (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_randomvec (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_strreplace (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_strireplace (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_randomvector (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -311,9 +311,9 @@ void QCBUILTIN PF_fopen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
void QCBUILTIN PF_FindString (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_FindFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_FindFlags (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_findchain (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_findchainfloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_findchainflags (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_bitshift(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_Abort(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);

View file

@ -2045,6 +2045,62 @@ mleaf_t *Q1BSP_LeafForPoint (model_t *model, vec3_t p)
return model->leafs + Q1BSP_LeafnumForPoint(model, p);
}
static void Q1BSP_ClustersInSphere_Union(mleaf_t *firstleaf, vec3_t center, float radius, mnode_t *node, qbyte *out, qbyte *unionwith)
{ //this is really for rtlights.
float t1, t2;
mplane_t *plane;
while (1)
{
if (node->contents < 0)
{ //leaf! mark/merge it.
size_t c = (mleaf_t *)node - firstleaf;
if (unionwith)
out[c>>3] |= (1<<(c&7)) & unionwith[c>>3];
else
out[c>>3] |= (1<<(c&7));
return;
}
plane = node->plane;
if (plane->type < 3)
t1 = center[plane->type] - plane->dist;
else
t1 = DotProduct (plane->normal, center) - plane->dist;
t2 = t1 - radius;
t1 = t1 + radius;
//if the sphere is fully to one side, only walk that side.
if (t1 > 0 && t2 > 0)
{
node = node->children[0];
continue;
}
if (t1 < 0 && t2 < 0)
{
node = node->children[1];
continue;
}
//both sides are within the sphere
Q1BSP_ClustersInSphere_Union(firstleaf, center, radius, node->children[0], out, unionwith);
node = node->children[1];
continue;
}
}
static qbyte *Q1BSP_ClustersInSphere(model_t *mod, vec3_t center, float radius, pvsbuffer_t *pvsbuffer, qbyte *unionwith)
{
if (!mod)
Sys_Error ("Mod_PointInLeaf: bad model");
if (!mod->nodes)
return NULL;
if (pvsbuffer->buffersize < mod->pvsbytes)
pvsbuffer->buffer = BZ_Realloc(pvsbuffer->buffer, pvsbuffer->buffersize=mod->pvsbytes);
Q_memset (pvsbuffer->buffer, 0, mod->pvsbytes);
Q1BSP_ClustersInSphere_Union(mod->leafs-1, center, radius, mod->nodes, pvsbuffer->buffer, NULL);//unionwith);
return pvsbuffer->buffer;
}
//returns the leaf number, which is used as a direct bit index into the pvs.
//-1 for invalid
static int Q1BSP_ClusterForPoint (model_t *model, vec3_t p)
@ -2103,6 +2159,7 @@ void Q1BSP_SetModelFuncs(model_t *mod)
mod->funcs.StainNode = NULL;
mod->funcs.MarkLights = NULL;
mod->funcs.ClustersInSphere = Q1BSP_ClustersInSphere;
mod->funcs.ClusterForPoint = Q1BSP_ClusterForPoint;
mod->funcs.ClusterPVS = Q1BSP_ClusterPVS;
// mod->funcs.ClusterPHS = Q1BSP_ClusterPHS;

View file

@ -977,7 +977,8 @@ void D3D11BE_UnbindAllTextures(void)
}
}
const GUID DECLSPEC_SELECTANY IID_ID3D11Texture2D = { 0x6f15aaf2, 0xd208, 0x4e89, { 0x9a,0xb4,0x48,0x95,0x35,0xd3,0x4f,0x9c } };
#define IID_ID3D11Texture2D gahzomgwtf
static const GUID IID_ID3D11Texture2D = { 0x6f15aaf2, 0xd208, 0x4e89, { 0x9a,0xb4,0x48,0x95,0x35,0xd3,0x4f,0x9c } };
static texid_t T_Gen_CurrentRender(void)
{

View file

@ -492,7 +492,7 @@ qboolean D3D11Shader_CreateProgram (program_t *prog, const char *name, unsigned
t++;
nl = strchr(t, '\n');
if (!nl)
nl = nl+strlen(nl);
nl = t+strlen(t);
if (nl && nl != t)
{

View file

@ -352,7 +352,6 @@ Global
{4735677B-6D5A-4BE6-A945-CB32DEADBEEF}.GLRelease|Win32.ActiveCfg = Release|Win32
{4735677B-6D5A-4BE6-A945-CB32DEADBEEF}.GLRelease|x64.ActiveCfg = Release|Win32
{4735677B-6D5A-4BE6-A945-CB32DEADBEEF}.MDebug|Win32.ActiveCfg = Debug|Win32
{4735677B-6D5A-4BE6-A945-CB32DEADBEEF}.MDebug|Win32.Build.0 = Debug|Win32
{4735677B-6D5A-4BE6-A945-CB32DEADBEEF}.MDebug|x64.ActiveCfg = Release|Win32
{4735677B-6D5A-4BE6-A945-CB32DEADBEEF}.MinGLDebug|Win32.ActiveCfg = Debug|Win32
{4735677B-6D5A-4BE6-A945-CB32DEADBEEF}.MinGLDebug|x64.ActiveCfg = Debug|Win32

View file

@ -93,7 +93,7 @@ struct {
program_t *programfixedemu[8];
texid_t tex_gbuf[2];
texid_t tex_gbuf[GBUFFER_COUNT];
int fbo_current; //the one currently being rendered to
texid_t tex_sourcecol; /*this is used by $sourcecolour tgen*/
texid_t tex_sourcedepth;
@ -278,16 +278,11 @@ void GLBE_PolyOffsetStencilShadow
qglDisable(GL_POLYGON_OFFSET_FILL);
}
}
static void GLBE_PolyOffsetShadowMap
#ifdef BEF_PUSHDEPTH
(qboolean pushdepth)
#else
(void)
#endif
static void GLBE_PolyOffsetShadowMap(void)
{
extern cvar_t r_polygonoffset_shadowmap_offset, r_polygonoffset_shadowmap_factor;
polyoffset_t po;
#ifdef BEF_PUSHDEPTH
#if 0//def BEF_PUSHDEPTH
if (pushdepth)
{
/*some quake doors etc are flush with the walls that they're meant to be hidden behind, or plats the same height as the floor, etc
@ -913,7 +908,7 @@ void GLBE_RenderShadowBuffer(unsigned int numverts, int vbo, vecV_t *verts, unsi
shaderstate.dummyvbo.indicies.gl.vbo = ibo;
if (shaderstate.mode != BEM_STENCIL)
GLBE_PolyOffsetShadowMap(false);
GLBE_PolyOffsetShadowMap();
if (shaderstate.allblackshader.glsl.handle)
{
@ -1266,6 +1261,9 @@ static void Shader_BindTextureForPass(int tmu, const shaderpass_t *pass)
case T_GEN_RIPPLEMAP:
t = shaderstate.tex_ripplemap[r_refdef.recurse];
break;
case T_GEN_GBUFFERCASE:
t = shaderstate.tex_gbuf[pass->texgen-T_GEN_GBUFFER0];
break;
}
GL_LazyBind(tmu, GL_TEXTURE_2D, t);
}
@ -3727,7 +3725,11 @@ void GLBE_SelectMode(backendmode_t mode)
#ifdef RTLIGHTS
case BEM_STENCIL:
/*BEM_STENCIL doesn't support mesh writing*/
#ifdef BEF_PUSHDEPTH
GLBE_PolyOffsetStencilShadow(false);
#else
GLBE_PolyOffsetStencilShadow();
#endif
if (gl_config_nofixedfunc && !shaderstate.allblackshader.glsl.handle)
{
@ -4182,7 +4184,9 @@ static void DrawMeshes(void)
break;
case BEM_GBUFFER:
altshader = shaderstate.curshader->bemoverrides[bemoverride_gbuffer];
if (altshader && altshader->prog)
if (altshader)
{
if (altshader->prog)
{
shaderstate.pendingcolourvbo = shaderstate.sourcevbo->colours[0].gl.vbo;
shaderstate.pendingcolourpointer = shaderstate.sourcevbo->colours[0].gl.addr;
@ -4192,6 +4196,18 @@ static void DrawMeshes(void)
shaderstate.pendingtexcoordpointer[0] = shaderstate.sourcevbo->texcoord.gl.addr;
BE_RenderMeshProgram(altshader, altshader->passes, altshader->prog);
}
else if (altshader->numpasses && altshader->passes[0].prog)
{
shaderstate.pendingcolourvbo = shaderstate.sourcevbo->colours[0].gl.vbo;
shaderstate.pendingcolourpointer = shaderstate.sourcevbo->colours[0].gl.addr;
shaderstate.colourarraytype = shaderstate.sourcevbo->colours_bytes?GL_UNSIGNED_BYTE:GL_FLOAT;
shaderstate.pendingtexcoordparts[0] = 2;
shaderstate.pendingtexcoordvbo[0] = shaderstate.sourcevbo->texcoord.gl.vbo;
shaderstate.pendingtexcoordpointer[0] = shaderstate.sourcevbo->texcoord.gl.addr;
BE_RenderMeshProgram(altshader, altshader->passes, altshader->passes[0].prog);
}
}
break;
#endif
case BEM_CREPUSCULAR:
@ -5132,7 +5148,7 @@ static void BE_UpdateLightmaps(void)
if (!TEXVALID(lm->lightmap_texture))
{
extern cvar_t gl_lightmap_nearest;
TEXASSIGN(lm->lightmap_texture, Image_CreateTexture("***lightmap***", NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP));
TEXASSIGN(lm->lightmap_texture, Image_CreateTexture(va("***lightmap %i***", lmidx), NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP));
qglGenTextures(1, &lm->lightmap_texture->num);
GL_MTBind(0, GL_TEXTURE_2D, lm->lightmap_texture);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@ -5500,8 +5516,12 @@ void GLBE_RenderToTexture(texid_t sourcecol, texid_t sourcedepth, texid_t destco
void GLBE_DrawLightPrePass(void)
{
cvar_t *var;
unsigned int i;
qboolean redefine = false;
texid_t depth, targets[countof(shaderstate.tex_gbuf)];
const char *s;
int w = r_refdef.pxrect.width, h = r_refdef.pxrect.height;
/*
walls(bumps) -> normalbuffer
lights+normalbuffer -> lightlevelbuffer
@ -5510,6 +5530,7 @@ void GLBE_DrawLightPrePass(void)
normalbuffer contains depth in the alpha channel. an actual depthbuffer is also generated at this time, which is used for depth test stuff but not as a shader input.
*/
int oldfbo;
/*do portals*/
BE_SelectMode(BEM_STANDARD);
GLBE_SubmitMeshes(cl.worldmodel->batches, SHADER_SORT_PORTAL, SHADER_SORT_PORTAL);
@ -5517,15 +5538,15 @@ void GLBE_DrawLightPrePass(void)
BE_SelectMode(BEM_GBUFFER);
for (i = 0; i < countof(shaderstate.tex_gbuf); i++)
{
if (!TEXVALID(shaderstate.tex_gbuf[i]) || vid.fbpwidth != shaderstate.tex_gbuf[i]->width || vid.fbpheight != shaderstate.tex_gbuf[i]->height)
if (!TEXVALID(shaderstate.tex_gbuf[i]) || w != shaderstate.tex_gbuf[i]->width || h != shaderstate.tex_gbuf[i]->height)
{
if (!shaderstate.tex_gbuf[i])
{
shaderstate.tex_gbuf[i] = Image_CreateTexture(va("***prepass %u***", i), NULL, 0);
shaderstate.tex_gbuf[i] = Image_CreateTexture(va("***gbuffer %u***", i), NULL, IF_CLAMP|IF_NEAREST|IF_NOMIPMAP|IF_RENDERTARGET);
qglGenTextures(1, &shaderstate.tex_gbuf[i]->num);
}
shaderstate.tex_gbuf[i]->width = vid.fbpwidth;
shaderstate.tex_gbuf[i]->height = vid.fbpheight;
shaderstate.tex_gbuf[i]->width = w;
shaderstate.tex_gbuf[i]->height = h;
redefine = true;
}
}
@ -5533,47 +5554,112 @@ void GLBE_DrawLightPrePass(void)
//something changed, redefine the textures.
if (redefine)
{
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_gbuf[1]);
qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, vid.fbpwidth, vid.fbpheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
static const char *defualtfmts[countof(shaderstate.tex_gbuf)] =
//depth, normals, difflight, speclight
{"depth", "rgba16f", "rgba16f", "rgba8", "", "", "", ""};
for (i = 0; i < countof(shaderstate.tex_gbuf); i++)
{
GLint ifmt = 0;
GLenum dfmt = GL_RGBA;
var = Cvar_Get(va("gl_deferred_gbuffmt_%i", i), defualtfmts[i]?defualtfmts[i]:"", 0, "Deferred Rendering");
if (!var)
continue;
if (!strcmp(var->string, "rgba32f"))
ifmt = GL_RGBA32F_ARB;
else if (!strcmp(var->string, "rgba16f"))
ifmt = GL_RGBA16F_ARB;
// else if (!strcmp(var->string, "rgba8s"))
// ifmt = GL_RGBA8_SNORM;
else if (!strcmp(var->string, "depth"))
{
ifmt = GL_DEPTH_COMPONENT;
dfmt = GL_DEPTH_COMPONENT;
}
else if (!strcmp(var->string, "depth16"))
{
ifmt = GL_DEPTH_COMPONENT16_ARB;
dfmt = GL_DEPTH_COMPONENT;
}
else if (!strcmp(var->string, "depth24"))
{
ifmt = GL_DEPTH_COMPONENT24_ARB;
dfmt = GL_DEPTH_COMPONENT;
}
else if (!strcmp(var->string, "depth32"))
{
ifmt = GL_DEPTH_COMPONENT32_ARB;
dfmt = GL_DEPTH_COMPONENT;
}
else if (!strcmp(var->string, "rgba8") || *var->string)
ifmt = GL_RGBA8;
else
continue;
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_gbuf[0]);
qglTexImage2D(GL_TEXTURE_2D, 0, (r_lightprepass==2)?GL_RGBA32F_ARB:GL_RGBA16F_ARB, vid.fbpwidth, vid.fbpheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
shaderstate.tex_gbuf[i]->status = TEX_LOADED;
GL_MTBind(0, GL_TEXTURE_2D, shaderstate.tex_gbuf[i]);
qglTexImage2D(GL_TEXTURE_2D, 0, ifmt, w, h, 0, dfmt, GL_UNSIGNED_BYTE, NULL);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
}
/*set the FB up to draw surface info*/
oldfbo = GLBE_FBO_Update(&shaderstate.fbo_lprepass, FBO_RB_DEPTH, &shaderstate.tex_gbuf[0], 1, r_nulltex, vid.fbpwidth, vid.fbpheight, 0);
GL_ForceDepthWritable();
//FIXME: should probably clear colour buffer too.
qglClear(GL_DEPTH_BUFFER_BIT);
var = Cvar_Get2("gl_deferred_pre_depth", "0", 0, "gbuffer index used for depth. negative means to use an annonamous renderbuffer", "Deferred Rendering");
if (var->ival < 0 || var->ival >= countof(shaderstate.tex_gbuf))
depth = r_nulltex;
else
depth = shaderstate.tex_gbuf[var->ival];
var = Cvar_Get2("gl_deferred_pre_targets", "1", 0, "space-separated list of gbuffer indexes to use for deferred surface information", "Deferred Rendering");
for (i = 0, s = var->string; *s && i < countof(targets); )
{
char token[32];
int b;
s = COM_ParseOut(s, token, sizeof(token));
if (!*token)
continue;
b = atoi(token);
if (b >= 0 && b < countof(shaderstate.tex_gbuf))
targets[i++] = shaderstate.tex_gbuf[b];
}
oldfbo = GLBE_FBO_Update(&shaderstate.fbo_lprepass, depth?FBO_TEX_DEPTH:FBO_RB_DEPTH, targets, i, depth, w, h, 0);
if (GL_FRAMEBUFFER_COMPLETE_EXT != qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT))
{
Con_Printf("Bad framebuffer\n");
return;
}
GL_ForceDepthWritable();
//FIXME: should probably clear colour buffer too.
qglClear(GL_DEPTH_BUFFER_BIT);
/*draw surfaces that can be drawn this way*/
GLBE_SubmitMeshes(cl.worldmodel->batches, SHADER_SORT_OPAQUE, SHADER_SORT_OPAQUE);
/*reconfigure - now drawing diffuse light info using the previous fb image as a source image*/
GLBE_FBO_Sources(shaderstate.tex_gbuf[0], r_nulltex);
GLBE_FBO_Update(&shaderstate.fbo_lprepass, FBO_RB_DEPTH, &shaderstate.tex_gbuf[1], 1, r_nulltex, vid.fbpwidth, vid.fbpheight, 0);
var = Cvar_Get2("gl_deferred_light_targets", "2 3", 0, "space-separated list of gbuffer indexes for lighting to write to", "Deferred Rendering");
for (i = 0, s = var->string; *s && i < countof(targets); )
{
char token[32];
int b;
s = COM_ParseOut(s, token, sizeof(token));
if (!*token)
continue;
b = atoi(token);
if (b >= 0 && b < countof(shaderstate.tex_gbuf))
targets[i++] = shaderstate.tex_gbuf[b];
}
GLBE_FBO_Update(&shaderstate.fbo_lprepass, depth?FBO_TEX_DEPTH:FBO_RB_DEPTH, targets, i, depth, w, h, 0);
BE_SelectMode(BEM_STANDARD);
qglClearColor (0,0,0,1);
qglClearColor (0,0,0,0);
qglClear(GL_COLOR_BUFFER_BIT);
GLBE_SelectEntity(&r_worldentity);
/*now draw the prelights*/
GLBE_SubmitMeshes(cl.worldmodel->batches, SHADER_SORT_PRELIGHT, SHADER_SORT_PRELIGHT);
GLBE_SubmitMeshes(cl.worldmodel->batches, SHADER_SORT_DEFERREDLIGHT, SHADER_SORT_DEFERREDLIGHT);
/*final reconfigure - now drawing final surface data onto true framebuffer*/
GLBE_FBO_Pop(oldfbo);
GLBE_FBO_Sources(shaderstate.tex_gbuf[1], r_nulltex);
if (!oldfbo)
qglDrawBuffer(GL_BACK);
@ -5587,7 +5673,6 @@ void GLBE_DrawLightPrePass(void)
Sh_DrawLights(r_refdef.scenevis);
#endif
GLBE_FBO_Sources(r_nulltex, r_nulltex);
qglClearColor (1,0,0,1);
}

View file

@ -297,6 +297,7 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips)
int i, j;
int nummips = mips->mipcount;
int encoding = mips->encoding;
qboolean compress;
if (gl_config.gles)
@ -421,6 +422,14 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips)
//2d or cubemaps
for (i = 0; i < nummips; i++)
{
//arb_texture_compression is core in gl1.3
//gles doesn't support autocompression as of gles3.
//only autocompress if we have actually have data (gl errors otherwise).
if (gl_config.arb_texture_compression && mips->mip[i].data)
compress = true;
else
compress = false;
if (tex->flags & IF_TEXTYPE)
{
targface = cubeface[i];
@ -453,29 +462,29 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips)
break;
//32bit formats
case PTI_RGBX8:
qglTexImage2D(targface, j, GL_RGB, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data);
qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGB_ARB:GL_RGB, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data);
break;
case PTI_RGBA8:
qglTexImage2D(targface, j, GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data);
qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGBA_ARB:GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data);
break;
case PTI_BGRX8:
qglTexImage2D(targface, j, GL_RGB, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data);
qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGB_ARB:GL_RGB, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data);
break;
default:
case PTI_BGRA8:
qglTexImage2D(targface, j, GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data);
qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGBA_ARB:GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data);
break;
case PTI_RGBX8_SRGB:
qglTexImage2D(targface, j, GL_SRGB_EXT, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data);
qglTexImage2D(targface, j, compress?GL_COMPRESSED_SRGB_EXT:GL_SRGB_EXT, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data);
break;
case PTI_RGBA8_SRGB:
qglTexImage2D(targface, j, GL_SRGB_ALPHA_EXT, mips->mip[i].width, mips->mip[i].height, 0, gl_config.gles?GL_SRGB_ALPHA_EXT:GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data);
qglTexImage2D(targface, j, compress?GL_COMPRESSED_SRGB_ALPHA_EXT:GL_SRGB_ALPHA_EXT, mips->mip[i].width, mips->mip[i].height, 0, gl_config.gles?GL_SRGB_ALPHA_EXT:GL_RGBA, GL_UNSIGNED_BYTE, mips->mip[i].data);
break;
case PTI_BGRX8_SRGB:
qglTexImage2D(targface, j, GL_SRGB_EXT, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data);
qglTexImage2D(targface, j, compress?GL_COMPRESSED_SRGB_EXT:GL_SRGB_EXT, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data);
break;
case PTI_BGRA8_SRGB:
qglTexImage2D(targface, j, GL_SRGB_ALPHA_EXT, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data);
qglTexImage2D(targface, j, compress?GL_COMPRESSED_SRGB_ALPHA_EXT:GL_SRGB_ALPHA_EXT, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, mips->mip[i].data);
break;
case PTI_RGBA16F:
@ -486,19 +495,19 @@ qboolean GL_LoadTextureMips(texid_t tex, const struct pendingtextureinfo *mips)
break;
//16bit formats
case PTI_RGBA4444:
qglTexImage2D(targface, j, GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, mips->mip[i].data);
qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGBA_ARB:GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, mips->mip[i].data);
break;
case PTI_RGBA5551:
qglTexImage2D(targface, j, GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, mips->mip[i].data);
qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGBA_ARB:GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, mips->mip[i].data);
break;
case PTI_ARGB4444:
qglTexImage2D(targface, j, GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV, mips->mip[i].data);
qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGBA_ARB:GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_4_4_4_4_REV, mips->mip[i].data);
break;
case PTI_ARGB1555:
qglTexImage2D(targface, j, GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV, mips->mip[i].data);
qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGBA_ARB:GL_RGBA, mips->mip[i].width, mips->mip[i].height, 0, GL_BGRA_EXT, GL_UNSIGNED_SHORT_1_5_5_5_REV, mips->mip[i].data);
break;
case PTI_RGB565:
qglTexImage2D(targface, j, GL_RGB, mips->mip[i].width, mips->mip[i].height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, mips->mip[i].data);
qglTexImage2D(targface, j, compress?GL_COMPRESSED_RGBA_ARB:GL_RGB, mips->mip[i].width, mips->mip[i].height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, mips->mip[i].data);
break;
//(desktop) compressed formats
case PTI_S3RGB1:

View file

@ -148,8 +148,10 @@ static void Mod_BatchList_f(void)
else if (batch->lightmap[1] >= 0)
Con_Printf(" %s lm=(%i:%i %i:%i) surfs=%u\n", batch->texture->shader->name, batch->lightmap[0], batch->lmlightstyle[0], batch->lightmap[1], batch->lmlightstyle[1], batch->maxmeshes);
else
#endif
if (batch->lightmap[1] >= 0)
#else
if (batch->lmlightstyle[0] != 255)
#endif
Con_Printf(" %s lm=(%i:%i) surfs=%u\n", batch->texture->shader->name, batch->lightmap[0], batch->lmlightstyle[0], batch->maxmeshes);
else
Con_Printf(" %s lm=%i surfs=%u verts=%i indexes=%i\n", batch->texture->shader->name, batch->lightmap[0], batch->maxmeshes, batch->vbo->vertcount, batch->vbo->indexcount);
@ -880,7 +882,7 @@ mleaf_t *Mod_PointInLeaf (model_t *model, vec3_t p)
}
if (!model->nodes)
return NULL;
#ifdef Q2BSPS
#if defined(Q2BSPS) || defined(Q3BSPS)
if (model->fromgame == fg_quake2 || model->fromgame == fg_quake3)
{
return model->leafs + CM_PointLeafnum(model, p);
@ -2502,10 +2504,13 @@ static void Mod_Batches_BuildModelMeshes(model_t *mod, int maxverts, int maxindi
build(mod, surf, bd);
if (lmmerge != 1)
{
for (sty = 0; sty < MAXRLIGHTMAPS; sty++)
{
if (surf->lightmaptexturenums[sty] >= 0)
{
if (mod->lightmaps.deluxemapping)
surf->lightmaptexturenums[sty] /= 2;
if (mesh->lmst_array[sty])
{
for (i = 0; i < mesh->numvertexes; i++)
@ -2515,6 +2520,9 @@ static void Mod_Batches_BuildModelMeshes(model_t *mod, int maxverts, int maxindi
}
}
surf->lightmaptexturenums[sty] /= lmmerge;
if (mod->lightmaps.deluxemapping)
surf->lightmaptexturenums[sty] *= 2;
}
}
}
}
@ -2598,7 +2606,6 @@ static int Mod_Batches_Generate(model_t *mod)
int merge = mod->lightmaps.merge;
if (!merge)
merge = 1;
mod->lightmaps.count = (mod->lightmaps.count+merge-1) & ~(merge-1);
mod->lightmaps.count /= merge;
mod->lightmaps.height *= merge;
@ -2726,7 +2733,6 @@ static int Mod_Batches_Generate(model_t *mod)
lbatch = batch;
}
return merge;
#undef lmmerge
}
@ -2810,6 +2816,13 @@ static void Mod_Batches_SplitLightmaps(model_t *mod, int lmmerge)
int i, j, sortid;
msurface_t *surf;
int sty;
int lmscale = 1;
if (mod->lightmaps.deluxemapping)
{
lmmerge *= 2;
lmscale *= 2;
}
for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++)
for (batch = mod->batches[sortid]; batch != NULL; batch = batch->next)
@ -2817,7 +2830,7 @@ static void Mod_Batches_SplitLightmaps(model_t *mod, int lmmerge)
surf = (msurface_t*)batch->mesh[0];
for (sty = 0; sty < MAXRLIGHTMAPS; sty++)
{
batch->lightmap[sty] = (surf->lightmaptexturenums[sty]>=0)?surf->lightmaptexturenums[sty]/lmmerge:surf->lightmaptexturenums[sty];
batch->lightmap[sty] = (surf->lightmaptexturenums[sty]>=0)?lmscale*(surf->lightmaptexturenums[sty]/lmmerge):surf->lightmaptexturenums[sty];
batch->lmlightstyle[sty] = surf->styles[sty];
}
@ -2826,7 +2839,7 @@ static void Mod_Batches_SplitLightmaps(model_t *mod, int lmmerge)
surf = (msurface_t*)batch->mesh[j];
for (sty = 0; sty < MAXRLIGHTMAPS; sty++)
{
int lm = (surf->lightmaptexturenums[sty]>=0)?surf->lightmaptexturenums[sty]/lmmerge:surf->lightmaptexturenums[sty];
int lm = (surf->lightmaptexturenums[sty]>=0)?lmscale*(surf->lightmaptexturenums[sty]/lmmerge):surf->lightmaptexturenums[sty];
if (lm != batch->lightmap[sty] ||
//fixme: we should merge later (reverted matching) surfaces into the prior batch
surf->styles[sty] != batch->lmlightstyle[sty] ||
@ -2844,7 +2857,7 @@ static void Mod_Batches_SplitLightmaps(model_t *mod, int lmmerge)
batch->maxmeshes = j;
for (sty = 0; sty < MAXRLIGHTMAPS; sty++)
{
int lm = (surf->lightmaptexturenums[sty]>=0)?surf->lightmaptexturenums[sty]/lmmerge:surf->lightmaptexturenums[sty];
int lm = (surf->lightmaptexturenums[sty]>=0)?lmscale*(surf->lightmaptexturenums[sty]/lmmerge):surf->lightmaptexturenums[sty];
nb->lightmap[sty] = lm;
nb->lmlightstyle[sty] = surf->styles[sty];
nb->vtlightstyle[sty] = surf->vlstyles[sty];
@ -3342,7 +3355,7 @@ TRACE(("dbg: Mod_LoadTextures: inittexturedescs\n"));
if (!*mt->name) //I HATE MAPPERS!
{
sprintf(mt->name, "unnamed%i", i);
Q_snprintfz(mt->name, sizeof(mt->name), "unnamed%i", i);
Con_DPrintf(CON_WARNING "warning: unnamed texture in %s, renaming to %s\n", loadmodel->name, mt->name);
}

View file

@ -35,7 +35,7 @@ typedef struct builddata_s builddata_t;
typedef enum {
SHADER_SORT_NONE,
SHADER_SORT_RIPPLE,
SHADER_SORT_PRELIGHT,
SHADER_SORT_DEFERREDLIGHT,
SHADER_SORT_PORTAL,
SHADER_SORT_SKY,
SHADER_SORT_OPAQUE,
@ -248,6 +248,7 @@ typedef struct {
int (*ClusterForPoint) (struct model_s *model, vec3_t point); //pvs index (leaf-1 for q1bsp). may be negative (ie: no pvs).
qbyte *(*ClusterPVS) (struct model_s *model, int cluster, pvsbuffer_t *pvsbuffer, pvsmerge_t merge);
qbyte *(*ClustersInSphere) (struct model_s *model, vec3_t point, float radius, pvsbuffer_t *pvsbuffer, qbyte *unionwith);
} modelfuncs_t;

View file

@ -195,7 +195,7 @@ mesh_t flashblend_mesh;
mesh_t flashblend_fsmesh;
shader_t *occluded_shader;
shader_t *flashblend_shader;
shader_t *lpplight_shader[LSHADER_MODES];
shader_t *deferredlight_shader[LSHADER_MODES];
void R_GenerateFlashblendTexture(void)
{
@ -275,7 +275,7 @@ void R_InitFlashblends(void)
"}\n"
"}\n"
);
memset(lpplight_shader, 0, sizeof(lpplight_shader));
memset(deferredlight_shader, 0, sizeof(deferredlight_shader));
}
static qboolean R_BuildDlightMesh(dlight_t *light, float colscale, float radscale, int dtype)
@ -521,14 +521,36 @@ void R_RenderDlights (void)
qboolean Sh_GenerateShadowMap(dlight_t *l);
qboolean Sh_CullLight(dlight_t *dl, qbyte *vvis);
void R_GenDlightMesh(struct batch_s *batch)
{
static mesh_t *meshptr;
dlight_t *l = cl_dlights + batch->surf_first;
vec3_t colour;
int lightflags = batch->surf_count;
BE_SelectDLight(l, l->color, l->axis, lightflags);
VectorCopy(l->color, colour);
if (l->style)
{
colour[0] *= cl_lightstyle[l->style-1].colours[0] * d_lightstylevalue[l->style-1]/255.0f;
colour[1] *= cl_lightstyle[l->style-1].colours[1] * d_lightstylevalue[l->style-1]/255.0f;
colour[2] *= cl_lightstyle[l->style-1].colours[2] * d_lightstylevalue[l->style-1]/255.0f;
}
else
{
colour[0] *= r_lightstylescale.value;
colour[1] *= r_lightstylescale.value;
colour[2] *= r_lightstylescale.value;
}
if (colour[0] < 0.001 && colour[1] < 0.001 && colour[2] < 0.001)
{ //just switch these off.
batch->meshes = 0;
return;
}
BE_SelectDLight(l, colour, l->axis, lightflags);
#ifdef RTLIGHTS
if (lightflags & LSHADER_SMAP)
{
@ -540,6 +562,11 @@ void R_GenDlightMesh(struct batch_s *batch)
BE_SelectEntity(&r_worldentity);
BE_SelectMode(BEM_STANDARD);
}
else if (Sh_CullLight(l, r_refdef.scenevis))
{
batch->meshes = 0;
return;
}
#endif
if (!R_BuildDlightMesh (l, 2, 1, 2))
@ -560,6 +587,8 @@ void R_GenDlightMesh(struct batch_s *batch)
meshptr = &flashblend_mesh;
}
batch->mesh = &meshptr;
RQuantAdd(RQUANT_RTLIGHT_DRAWN, 1);
}
void R_GenDlightBatches(batch_t *batches[])
{
@ -570,33 +599,24 @@ void R_GenDlightBatches(batch_t *batches[])
if (!r_lightprepass)
return;
if (!lpplight_shader[0])
if (!deferredlight_shader[0])
{
lpplight_shader[0] = R_RegisterShader("lpp_light", SUF_NONE,
const char *deferredlight_shader_code =
"{\n"
"deferredlight\n"
"surfaceparm nodlight\n"
"{\n"
"program lpp_light\n"
"{\n"
"map $sourcecolour\n"
"blendfunc gl_one gl_one\n"
"nodepthtest\n"
"map $gbuffer0\n" //depth
"map $gbuffer1\n" //normals.rgb specexp.a
"}\n"
"surfaceparm nodlight\n"
"lpp_light\n"
"}\n"
);
;
deferredlight_shader[0] = R_RegisterShader("deferredlight", SUF_NONE, deferredlight_shader_code);
#ifdef RTLIGHTS
lpplight_shader[LSHADER_SMAP] = R_RegisterShader("lpp_light#PCF", SUF_NONE,
"{\n"
"program lpp_light\n"
"{\n"
"map $sourcecolour\n"
"blendfunc gl_one gl_one\n"
"nodepthtest\n"
"}\n"
"surfaceparm nodlight\n"
"lpp_light\n"
"}\n"
);
deferredlight_shader[LSHADER_SMAP] = R_RegisterShader("deferredlight#PCF", SUF_NONE, deferredlight_shader_code);
#endif
}
@ -607,7 +627,10 @@ void R_GenDlightBatches(batch_t *batches[])
continue;
if (R_CullSphere(l->origin, l->radius))
{
RQuantAdd(RQUANT_RTLIGHT_CULL_FRUSTUM, 1);
continue;
}
lmode = 0;
#ifdef RTLIGHTS
@ -622,7 +645,7 @@ void R_GenDlightBatches(batch_t *batches[])
return;
b->flags = 0;
b->shader = lpplight_shader[lmode];
b->shader = deferredlight_shader[lmode];
sort = b->shader->sort;
b->buildmeshes = R_GenDlightMesh;
b->ent = &r_worldentity;

View file

@ -1350,6 +1350,9 @@ void R_Clear (qboolean fbo)
//for performance, we clear the depth at the same time we clear colour, so we can skip clearing depth here the first time around each frame.
//but for multiple scenes, we do need to clear depth still.
//fbos always get cleared depth, just in case (colour fbos may contain junk, but hey).
if (fbo && r_clear.ival)
qglClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
else
qglClear (GL_DEPTH_BUFFER_BIT);
}
if (!fbo)
@ -1713,8 +1716,6 @@ qboolean R_RenderScene_Cubemap(void)
r_refdef.viewangles[2] = saveang[2]+ang[i][2];
R_Clear (usefbo);
if (r_clear.ival)
qglClear(GL_COLOR_BUFFER_BIT);
GL_SetShaderState2D(false);

View file

@ -532,7 +532,7 @@ void GLBE_UploadAllLightmaps(void)
continue;
lm->modified = false;
if (!TEXVALID(lm->lightmap_texture))
TEXASSIGN(lm->lightmap_texture, Image_CreateTexture("***lightmap***", NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP));
TEXASSIGN(lm->lightmap_texture, Image_CreateTexture(va("***lightmap %i***", i), NULL, (gl_lightmap_nearest.ival?IF_NEAREST:IF_LINEAR)|IF_NOMIPMAP));
if (!lm->lightmap_texture->num)
qglGenTextures(1, &lm->lightmap_texture->num);
GL_MTBind(0, GL_TEXTURE_2D, lm->lightmap_texture);

View file

@ -83,7 +83,6 @@ char *COM_ParseExt (char **data_p, qboolean nl, qboolean comma)
int c;
int len;
char *data;
qboolean newlines = false;
COM_AssertMainThread("COM_ParseExt");
@ -106,16 +105,13 @@ skipwhite:
*data_p = NULL;
return "";
}
if (c == '\n')
newlines = true;
data++;
}
if (newlines && !nl)
if (c == '\n' && !nl)
{
*data_p = data;
return com_token;
}
data++;
}
// skip // comments
if (c == '/' && data[1] == '/')
@ -127,8 +123,8 @@ skipwhite:
// skip /* comments
if (c == '/' && data[1] == '*')
{
char *start = data;
data+=2;
newlines = true;
for(;data[0];)
{
if (data[0] == '*' && data[1] == '/')
@ -136,6 +132,11 @@ skipwhite:
data+=2;
break;
}
if (*data == '\n' && !nl)
{
*data_p = start;
return com_token;
}
data++;
}
goto skipwhite;
@ -297,6 +298,8 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr)
{
conditiontrue = false;
token++;
if (!*token)
token = COM_ParseExt(ptr, false, false);
}
if (*token >= '0' && *token <= '9')
@ -307,52 +310,52 @@ static qboolean Shader_EvaluateCondition(shader_t *shader, char **ptr)
token++;
if (*token == '#')
conditiontrue = conditiontrue == !!Shader_FloatArgument(shader, token);
lhs = !!Shader_FloatArgument(shader, token);
else if (!Q_stricmp(token, "lpp"))
conditiontrue = conditiontrue == r_lightprepass;
lhs = r_lightprepass;
else if (!Q_stricmp(token, "lightmap"))
conditiontrue = conditiontrue == !r_fullbright.value;
else if (!Q_stricmp(token, "deluxmap"))
conditiontrue = conditiontrue == r_deluxmapping;
lhs = !r_fullbright.value;
else if (!Q_stricmp(token, "deluxmap") || !Q_stricmp(token, "deluxe"))
lhs = r_deluxmapping;
else if (!Q_stricmp(token, "softwarebanding"))
conditiontrue = conditiontrue == r_softwarebanding;
lhs = r_softwarebanding;
//normalmaps are generated if they're not already known.
else if (!Q_stricmp(token, "normalmap"))
conditiontrue = conditiontrue == r_loadbumpmapping;
lhs = r_loadbumpmapping;
else if (!Q_stricmp(token, "vulkan"))
conditiontrue = conditiontrue == (qrenderer == QR_VULKAN);
lhs = (qrenderer == QR_VULKAN);
else if (!Q_stricmp(token, "opengl"))
conditiontrue = conditiontrue == (qrenderer == QR_OPENGL);
lhs = (qrenderer == QR_OPENGL);
else if (!Q_stricmp(token, "d3d8"))
conditiontrue = conditiontrue == (qrenderer == QR_DIRECT3D8);
lhs = (qrenderer == QR_DIRECT3D8);
else if (!Q_stricmp(token, "d3d9"))
conditiontrue = conditiontrue == (qrenderer == QR_DIRECT3D9);
lhs = (qrenderer == QR_DIRECT3D9);
else if (!Q_stricmp(token, "d3d11"))
conditiontrue = conditiontrue == (qrenderer == QR_DIRECT3D11);
lhs = (qrenderer == QR_DIRECT3D11);
else if (!Q_stricmp(token, "gles"))
conditiontrue = conditiontrue == ((qrenderer == QR_OPENGL) && sh_config.minver == 100);
lhs = ((qrenderer == QR_OPENGL) && sh_config.minver == 100);
else if (!Q_stricmp(token, "nofixed"))
conditiontrue = conditiontrue == sh_config.progs_required;
lhs = sh_config.progs_required;
else if (!Q_stricmp(token, "glsl"))
conditiontrue = conditiontrue == ((qrenderer == QR_OPENGL) && sh_config.progs_supported);
lhs = ((qrenderer == QR_OPENGL) && sh_config.progs_supported);
else if (!Q_stricmp(token, "hlsl"))
conditiontrue = conditiontrue == ((qrenderer == QR_DIRECT3D9 || qrenderer == QR_DIRECT3D11) && sh_config.progs_supported);
lhs = ((qrenderer == QR_DIRECT3D9 || qrenderer == QR_DIRECT3D11) && sh_config.progs_supported);
else if (!Q_stricmp(token, "haveprogram"))
conditiontrue = conditiontrue == !!shader->prog;
lhs = !!shader->prog;
else if (!Q_stricmp(token, "programs"))
conditiontrue = conditiontrue == sh_config.progs_supported;
lhs = sh_config.progs_supported;
else if (!Q_stricmp(token, "diffuse"))
conditiontrue = conditiontrue == true;
lhs = true;
else if (!Q_stricmp(token, "specular"))
conditiontrue = conditiontrue == false;
lhs = false;
else if (!Q_stricmp(token, "fullbright"))
conditiontrue = conditiontrue == false;
lhs = false;
else if (!Q_stricmp(token, "topoverlay"))
conditiontrue = conditiontrue == false;
lhs = false;
else if (!Q_stricmp(token, "loweroverlay"))
conditiontrue = conditiontrue == false;
lhs = false;
else
{
cv = Cvar_Get(token, "", 0, "Shader Conditions");
@ -425,6 +428,8 @@ static char *Shader_ParseString(char **ptr)
if (!ptr || !(*ptr))
return "";
while(**ptr == ' ' || **ptr == '\t')
*ptr+=1;
if (!**ptr || **ptr == '}')
return "";
@ -1004,8 +1009,8 @@ static void Shader_Sort ( shader_t *shader, shaderpass_t *pass, char **ptr )
shader->sort = SHADER_SORT_NEAREST;
else if( !Q_stricmp( token, "blend" ) )
shader->sort = SHADER_SORT_BLEND;
else if ( !Q_stricmp( token, "lpp_light" ) )
shader->sort = SHADER_SORT_PRELIGHT;
else if ( !Q_stricmp( token, "deferredlight" ) )
shader->sort = SHADER_SORT_DEFERREDLIGHT;
else if ( !Q_stricmp( token, "ripple" ) )
shader->sort = SHADER_SORT_RIPPLE;
else
@ -1015,9 +1020,9 @@ static void Shader_Sort ( shader_t *shader, shaderpass_t *pass, char **ptr )
}
}
static void Shader_Prelight ( shader_t *shader, shaderpass_t *pass, char **ptr )
static void Shader_Deferredlight ( shader_t *shader, shaderpass_t *pass, char **ptr )
{
shader->sort = SHADER_SORT_PRELIGHT;
shader->sort = SHADER_SORT_DEFERREDLIGHT;
}
static void Shader_Portal ( shader_t *shader, shaderpass_t *pass, char **ptr )
@ -2305,6 +2310,56 @@ static void Shader_LowerMap(shader_t *shader, shaderpass_t *pass, char **ptr)
shader->defaulttextures->loweroverlay = Shader_FindImage(token, flags);
}
static void Shaderpass_QF_Material(shader_t *shader, shaderpass_t *pass, char **ptr)
{
unsigned int flags;
char *progname = "defaultwall";
char *token;
char *hash = strchr(shader->name, '#');
if (hash)
{
//pass the # postfixes from the shader name onto the generic glsl to use
char newname[512];
Q_snprintfz(newname, sizeof(newname), "%s%s", progname, hash);
pass->prog = Shader_FindGeneric(newname, qrenderer);
}
else
pass->prog = Shader_FindGeneric(progname, qrenderer);
token = Shader_ParseString(ptr);
if (*token && strcmp(token, "-"))
{
flags = Shader_SetImageFlags (shader, NULL, &token);
if (*token)
shader->defaulttextures->base = Shader_FindImage(token, flags);
else
{
token = shader->name;
if (hash)
*hash = 0;
shader->defaulttextures->base = Shader_FindImage(token, flags);
if (hash)
*hash = '#';
}
}
if (*token)
token = Shader_ParseString(ptr);
if (*token && strcmp(token, "-"))
{
flags = Shader_SetImageFlags (shader, NULL, &token);
shader->defaulttextures->bump = Shader_FindImage(token, flags);
}
if (*token)
token = Shader_ParseString(ptr);
if (*token && strcmp(token, "-"))
{
flags = Shader_SetImageFlags (shader, NULL, &token);
shader->defaulttextures->specular = Shader_FindImage(token, flags);
}
}
static qboolean Shaderpass_MapGen (shader_t *shader, shaderpass_t *pass, char *tname);
static void Shader_ProgMap(shader_t *shader, shaderpass_t *pass, char **ptr)
{
@ -2479,21 +2534,23 @@ static void Shader_BEMode(shader_t *shader, shaderpass_t *pass, char **ptr)
static shaderkey_t shaderkeys[] =
{
{"cull", Shader_Cull},
{"skyparms", Shader_SkyParms},
{"fogparms", Shader_FogParms},
{"surfaceparm", Shader_SurfaceParm},
{"nomipmaps", Shader_NoMipMaps},
{"nopicmip", Shader_NoPicMip},
{"polygonoffset", Shader_PolygonOffset},
{"sort", Shader_Sort},
{"deformvertexes", Shader_DeformVertexes},
{"portal", Shader_Portal},
{"entitymergable", Shader_EntityMergable},
#define Q3 NULL
{"cull", Shader_Cull, Q3},
{"skyparms", Shader_SkyParms, Q3},
{"fogparms", Shader_FogParms, Q3},
{"surfaceparm", Shader_SurfaceParm, Q3},
{"nomipmaps", Shader_NoMipMaps, Q3},
{"nopicmip", Shader_NoPicMip, Q3},
{"polygonoffset", Shader_PolygonOffset, Q3},
{"sort", Shader_Sort, Q3},
{"deformvertexes", Shader_DeformVertexes, Q3},
{"portal", Shader_Portal, Q3},
{"entitymergable", Shader_EntityMergable, Q3},
//fte extensions
{"clutter", Shader_ClutterParms, "fte"},
{"lpp_light", Shader_Prelight, "fte"},
{"deferredlight", Shader_Deferredlight, "fte"}, //(sort = prelight)
// {"lpp_light", Shader_Deferredlight, "fte"}, //(sort = prelight)
{"glslprogram", Shader_GLSLProgramName, "fte"},
{"program", Shader_ProgramName, "fte"}, //gl or d3d
{"hlslprogram", Shader_HLSL9ProgramName, "fte"}, //for d3d
@ -2511,6 +2568,10 @@ static shaderkey_t shaderkeys[] =
{"lowermap", Shader_LowerMap, "fte"},
{"reflectmask", Shader_ReflectMask, "fte"},
/*simpler parsing for fte shaders*/
{"progblendfunc", Shader_ProgBlendFunc, "fte"},
{"progmap", Shader_ProgMap, "fte"},
//dp compat
{"reflectcube", Shader_ReflectCube, "dp"},
{"camera", Shader_DP_Camera, "dp"},
@ -2520,8 +2581,8 @@ static shaderkey_t shaderkeys[] =
{"offsetmapping", Shader_DP_OffsetMapping, "dp"},
{"noshadow", NULL, "dp"},
{"polygonoffset", NULL, "dp"},
{"glossintensitymod",Shader_DP_GlossScale, "dp"}, //scales r_shadow_glossintensity(=1), aka: gl_specular
{"glossexponentmod",Shader_DP_GlossExponent, "dp"}, //scales r_shadow_glossexponent(=32)
{"glossintensitymod", Shader_DP_GlossScale, "dp"}, //scales r_shadow_glossintensity(=1), aka: gl_specular
{"glossexponentmod", Shader_DP_GlossExponent, "dp"}, //scales r_shadow_glossexponent(=32)
/*doom3 compat*/
{"diffusemap", Shader_DiffuseMap, "doom3"}, //macro for "{\nstage diffusemap\nmap <map>\n}"
@ -2534,9 +2595,20 @@ static shaderkey_t shaderkeys[] =
{"nooverlays", NULL, "doom3"},
{"nofragment", NULL, "doom3"},
/*simpler parsing for fte shaders*/
{"progblendfunc", Shader_ProgBlendFunc, "fte"},
{"progmap", Shader_ProgMap, "fte"},
/*qfusion / warsow compat*/
// {"skyparms2", NULL, "qf"}, //skyparms without the underscore.
// {"skyparmssides", NULL, "qf"}, //skyparms with explicitly-named faces
// {"nocompress", NULL, "qf"}, //disables opportunistic compression (doesn't affect compressed source images, apparently)
// {"nofiltering", NULL, "qf"}, //misnomer. there is always 'filtering'. this means to use nearest filtering for min and mag, as well as no mipmaps.
// {"smallestmipmapsize", NULL, "qf"}, //mips with a size less than the specified value are dropped.
// {"stenciltest", NULL, "qf"}, //enables GL_STENCIL_TEST, which is special-case stuff that I see no reason to support
// {"offsetmappingscale", NULL, "qf"},
// {"glossexponent", NULL, "qf"},
// {"glossintensity", NULL, "qf"},
// {"template", NULL, "qf"}, //parses some other shader, with $3 etc arg expansion
{"skip", NULL, "qf"}, //just skips the line. acts like a comment. no idea why they can't just use a comment.
// {"softparticle", NULL, "qf"}, //uses screen depth, if possible.
// {"forceworldoutlines", NULL, "qf"}, //looks like an ugly hack to me.
{NULL, NULL}
};
@ -2641,6 +2713,13 @@ static qboolean Shaderpass_MapGen (shader_t *shader, shaderpass_t *pass, char *t
{
pass->texgen = T_GEN_SOURCEDEPTH;
}
else if (!Q_strnicmp (tname, "$gbuffer", 8))
{
unsigned idx = strtoul(tname+8, &tname, 10);
if (*tname || idx >= GBUFFER_COUNT)
return false;
pass->texgen = T_GEN_GBUFFER0 + idx;
}
else if (!Q_stricmp (tname, "$reflection"))
{
shader->flags |= SHADER_HASREFLECT;
@ -2740,14 +2819,13 @@ static void Shaderpass_Map (shader_t *shader, shaderpass_t *pass, char **ptr)
}
}
static void Shaderpass_AnimMap (shader_t *shader, shaderpass_t *pass, char **ptr)
static void Shaderpass_AnimMap_Flag (shader_t *shader, shaderpass_t *pass, char **ptr, unsigned int flags)
{
int flags;
char *token;
texid_t image;
qboolean isdiffuse = false;
flags = Shader_SetImageFlags (shader, pass, NULL);
flags |= Shader_SetImageFlags (shader, pass, NULL);
if (pass->tcgen == TC_GEN_UNSPECIFIED)
pass->tcgen = TC_GEN_BASE;
@ -2797,6 +2875,14 @@ static void Shaderpass_AnimMap (shader_t *shader, shaderpass_t *pass, char **ptr
}
}
}
static void Shaderpass_AnimMap (shader_t *shader, shaderpass_t *pass, char **ptr)
{
Shaderpass_AnimMap_Flag(shader, pass, ptr, 0);
}
static void Shaderpass_QF_AnimClampMap (shader_t *shader, shaderpass_t *pass, char **ptr)
{
Shaderpass_AnimMap_Flag(shader, pass, ptr, IF_CLAMP);
}
static void Shaderpass_ClampMap (shader_t *shader, shaderpass_t *pass, char **ptr)
{
@ -3449,27 +3535,31 @@ static void Shaderpass_CubeMap(shader_t *shader, shaderpass_t *pass, char **ptr)
static shaderkey_t shaderpasskeys[] =
{
{"rgbgen", Shaderpass_RGBGen },
{"blendfunc", Shaderpass_BlendFunc },
{"depthfunc", Shaderpass_DepthFunc },
{"depthwrite", Shaderpass_DepthWrite },
{"nodepthtest", Shaderpass_NoDepthTest },
{"nodepth", Shaderpass_NoDepth },
{"alphafunc", Shaderpass_AlphaFunc },
{"tcmod", Shaderpass_TcMod },
{"map", Shaderpass_Map },
{"animmap", Shaderpass_AnimMap },
{"clampmap", Shaderpass_ClampMap },
{"videomap", Shaderpass_VideoMap },
{"tcgen", Shaderpass_TcGen },
#define Q3 NULL
{"rgbgen", Shaderpass_RGBGen, Q3},
{"alphagen", Shaderpass_AlphaGen, Q3},
{"blendfunc", Shaderpass_BlendFunc, Q3},
{"depthfunc", Shaderpass_DepthFunc, Q3},
{"depthwrite", Shaderpass_DepthWrite, Q3},
{"alphafunc", Shaderpass_AlphaFunc, Q3},
{"tcmod", Shaderpass_TcMod, Q3},
{"map", Shaderpass_Map, Q3},
{"animmap", Shaderpass_AnimMap, Q3},
{"clampmap", Shaderpass_ClampMap, Q3},
{"videomap", Shaderpass_VideoMap, Q3},
{"tcgen", Shaderpass_TcGen, Q3},
{"texgen", Shaderpass_TcGen, Q3},
{"detail", Shaderpass_Detail, Q3},
{"nodepthtest", Shaderpass_NoDepthTest, NULL},
{"nodepth", Shaderpass_NoDepth, NULL},
{"envmap", Shaderpass_EnvMap, "rscript"},//for alienarena
{"nolightmap", Shaderpass_NoLightMap, "rscript"},//for alienarena
{"scale", Shaderpass_Scale, "rscript"},//for alienarena
{"scroll", Shaderpass_Scroll, "rscript"},//for alienarena
{"alphagen", Shaderpass_AlphaGen, "rscript"},
{"alphashift", Shaderpass_AlphaShift, "rscript"},//for alienarena
{"alphamask", Shaderpass_AlphaMask, "rscript"},//for alienarena
{"detail", Shaderpass_Detail, "rscript"},
{"program", Shaderpass_ProgramName, "fte"},
@ -3488,6 +3578,20 @@ static shaderkey_t shaderpasskeys[] =
{"green", Shaderpass_Green, "doom3"},
{"blue", Shaderpass_Blue, "doom3"},
{"alpha", Shaderpass_Alpha, "doom3"},
//qfusion/warsow compat
{"material", Shaderpass_QF_Material, "qf"},
{"animclampmap",Shaderpass_QF_AnimClampMap, "qf"},
// {"cubemap", Shaderpass_CubeMap, "qf"},
// {"shadecubemap",Shaderpass_ShadeCubeMap, "qf"},
// {"surroundmap", Shaderpass_SurroundMap, "qf"},
// {"distortion", Shaderpass_Distortion, "qf"},
// {"celshade", Shaderpass_Celshade, "qf"},
// {"grayscale", Shaderpass_Greyscale, "qf"},
// {"greyscale", Shaderpass_Greyscale, "qf"},
// {"skip", Shaderpass_Skip, "qf"},
{NULL, NULL}
};
@ -4000,17 +4104,106 @@ void Shader_FixupProgPasses(shader_t *shader, shaderpass_t *pass)
shader->numpasses = (pass-shader->passes)+pass->numMergedPasses;
}
struct scondinfo_s
{
int depth;
int level[8];
#define COND_IGNORE 1
#define COND_IGNOREPARENT 2
#define COND_ALLOWELSE 4
#define COND_TAKEN 8
};
static qboolean Shader_Conditional_Read(shader_t *shader, struct scondinfo_s *cond, char *token, char **ptr)
{
if (!Q_stricmp(token, "if"))
{
if (cond->depth+1 == countof(cond->level))
{
Con_Printf("if statements nest too deeply in shader %s\n", shader->name);
*ptr += strlen(*ptr);
return true;
}
cond->depth++;
cond->level[cond->depth] = (Shader_EvaluateCondition(shader, ptr)?0:COND_IGNORE);
cond->level[cond->depth] |= COND_ALLOWELSE;
if (cond->level[cond->depth-1] & (COND_IGNORE|COND_IGNOREPARENT))
cond->level[cond->depth] |= COND_IGNOREPARENT; //if ignoring the parent, ignore this one too, even if valid
if (!(cond->level[cond->depth] & (COND_IGNORE|COND_IGNOREPARENT)))
cond->level[cond->depth] |= COND_TAKEN; //if we're not ignoring the contained commands then flag it so we don't take any elifs/elses
}
else if (!Q_stricmp(token, "elif"))
{
if (cond->level[cond->depth] & COND_ALLOWELSE)
{
if (cond->level[cond->depth] & COND_TAKEN)
{ //if we took the if/elif then don't take this elif either
Shader_EvaluateCondition(shader, ptr);
cond->level[cond->depth] = COND_ALLOWELSE|COND_TAKEN|COND_IGNORE;
}
else
{
cond->level[cond->depth] = (Shader_EvaluateCondition(shader, ptr)?0:COND_IGNORE);
cond->level[cond->depth] |= COND_ALLOWELSE;
}
if (cond->level[cond->depth-1] & (COND_IGNORE|COND_IGNOREPARENT))
cond->level[cond->depth] |= COND_IGNOREPARENT;
if (!(cond->level[cond->depth] & (COND_IGNORE|COND_IGNOREPARENT)))
cond->level[cond->depth] |= COND_TAKEN;
}
else
{
Con_Printf("unexpected elif statement in shader %s\n", shader->name);
*ptr += strlen(*ptr);
}
}
else if (!Q_stricmp(token, "endif"))
{
if (!cond->depth)
{
Con_Printf("endif without if in shader %s\n", shader->name);
*ptr += strlen(*ptr);
return true;
}
cond->depth--;
}
else if (!Q_stricmp(token, "else"))
{
if (cond->level[cond->depth] & COND_ALLOWELSE)
{
if (cond->level[cond->depth] & COND_TAKEN)
cond->level[cond->depth] |= COND_IGNORE;
else
cond->level[cond->depth] ^= COND_IGNORE;
cond->level[cond->depth] &= ~COND_ALLOWELSE;
}
else
{
Con_Printf("unexpected else statement in shader %s\n", shader->name);
*ptr += strlen(*ptr);
}
}
else if (cond->level[cond->depth] & (COND_IGNORE|COND_IGNOREPARENT))
{
//eat it
while (ptr)
{
token = COM_ParseExt(ptr, false, true);
if ( !token[0] )
break;
}
}
else
return false;
return true;
}
void Shader_Readpass (shader_t *shader, char **ptr)
{
char *token;
shaderpass_t *pass;
static shader_t dummy;
int conddepth = 0;
int cond[8] = {0};
struct scondinfo_s cond = {0};
unsigned int oldflags = shader->flags;
#define COND_IGNORE 1
#define COND_IGNOREPARENT 2
#define COND_ALLOWELSE 4
if ( shader->numpasses >= SHADER_PASS_MAX )
{
@ -4047,49 +4240,7 @@ void Shader_Readpass (shader_t *shader, char **ptr)
{
continue;
}
else if (!Q_stricmp(token, "if"))
{
if (conddepth+1 == sizeof(cond)/sizeof(cond[0]))
{
Con_Printf("if statements nest too deeply in shader %s\n", shader->name);
break;
}
conddepth++;
cond[conddepth] = (Shader_EvaluateCondition(shader, ptr)?0:COND_IGNORE);
cond[conddepth] |= COND_ALLOWELSE;
if (cond[conddepth-1] & (COND_IGNORE|COND_IGNOREPARENT))
cond[conddepth] |= COND_IGNOREPARENT;
}
else if (!Q_stricmp(token, "endif"))
{
if (!conddepth)
{
Con_Printf("endif without if in shader %s\n", shader->name);
break;
}
conddepth--;
}
else if (!Q_stricmp(token, "else"))
{
if (cond[conddepth] & COND_ALLOWELSE)
{
cond[conddepth] ^= COND_IGNORE;
cond[conddepth] &= ~COND_ALLOWELSE;
}
else
Con_Printf("unexpected else statement in shader %s\n", shader->name);
}
else if (cond[conddepth] & (COND_IGNORE|COND_IGNOREPARENT))
{
//eat it
while (ptr)
{
token = COM_ParseExt(ptr, false, true);
if ( !token[0] )
break;
}
}
else
else if (!Shader_Conditional_Read(shader, &cond, token, ptr))
{
if ( token[0] == '}' )
break;
@ -4102,7 +4253,7 @@ void Shader_Readpass (shader_t *shader, char **ptr)
if (!pass->numMergedPasses)
pass->numMergedPasses = 1;
if (conddepth)
if (cond.depth)
{
Con_Printf("if statements without endif in shader %s\n", shader->name);
}
@ -5520,17 +5671,18 @@ void Shader_DefaultBSPLM(const char *shortname, shader_t *s, const void *args)
{
builtin = (
"{\n"
"fte_program lpp_wall\n"
"{\n"
"map $sourcecolour\n"
"fte_program lpp_wall\n"
"map $gbuffer2\n" //diffuse lighting info
"map $gbuffer3\n" //specular lighting info
"}\n"
//this is drawn during the gbuffer pass to prepare it
//this is drawn during the initial gbuffer pass to prepare it
"fte_bemode gbuffer\n"
"{\n"
"fte_program lpp_depthnorm\n"
"{\n"
"map $normalmap\n"
"fte_program lpp_depthnorm\n"
// "map $normalmap\n"
"tcgen base\n"
"}\n"
"}\n"
@ -6122,6 +6274,29 @@ void Shader_DefaultSkin(const char *shortname, shader_t *s, const void *args)
);
return;
}
if (r_lightprepass)
{
Shader_DefaultScript(shortname, s,
"{\n"
"{\n"
"fte_program lpp_wall\n"
"map $gbuffer2\n" //diffuse lighting info
"map $gbuffer3\n" //specular lighting info
"}\n"
//this is drawn during the initial gbuffer pass to prepare it
"fte_bemode gbuffer\n"
"{\n"
"{\n"
"fte_program lpp_depthnorm\n"
"tcgen base\n"
"}\n"
"}\n"
"}\n"
);
return;
}
if (r_tessellation.ival && sh_config.progs_supported)
{
Shader_DefaultScript(shortname, s,
@ -6229,14 +6404,10 @@ void Shader_Default2D(const char *shortname, shader_t *s, const void *genargs)
}
}
qboolean Shader_ReadShaderTerms(shader_t *s, char **shadersource, int parsemode, int *conddepth, int maxconddepth, int *cond)
static qboolean Shader_ReadShaderTerms(shader_t *s, char **shadersource, int parsemode, struct scondinfo_s *cond)
{
char *token;
#define COND_IGNORE 1
#define COND_IGNOREPARENT 2
#define COND_ALLOWELSE 4
if (!*shadersource)
return false;
@ -6244,49 +6415,7 @@ qboolean Shader_ReadShaderTerms(shader_t *s, char **shadersource, int parsemode,
if ( !token[0] )
return true;
else if (!Q_stricmp(token, "if"))
{
if (*conddepth+1 == maxconddepth)
{
Con_Printf("if statements nest too deeply in shader %s\n", s->name);
return false;
}
*conddepth+=1;
cond[*conddepth] = (!Shader_EvaluateCondition(s, shadersource)?COND_IGNORE:0);
cond[*conddepth] |= COND_ALLOWELSE;
if (cond[*conddepth-1] & (COND_IGNORE|COND_IGNOREPARENT))
cond[*conddepth] |= COND_IGNOREPARENT;
}
else if (!Q_stricmp(token, "endif"))
{
if (!*conddepth)
{
Con_Printf("endif without if in shader %s\n", s->name);
return false;
}
*conddepth-=1;
}
else if (!Q_stricmp(token, "else"))
{
if (cond[*conddepth] & COND_ALLOWELSE)
{
cond[*conddepth] ^= COND_IGNORE;
cond[*conddepth] &= ~COND_ALLOWELSE;
}
else
Con_Printf("unexpected else statement in shader %s\n", s->name);
}
else if (cond[*conddepth] & (COND_IGNORE|COND_IGNOREPARENT))
{
//eat it.
while (**shadersource)
{
token = COM_ParseExt(shadersource, false, true);
if ( !token[0] )
break;
}
}
else
else if (!Shader_Conditional_Read(s, cond, token, shadersource))
{
int i;
for (i = 0; shadermacros[i].name; i++)
@ -6297,7 +6426,6 @@ qboolean Shader_ReadShaderTerms(shader_t *s, char **shadersource, int parsemode,
int argn = 0;
char *body;
char arg[SHADER_MACRO_ARGS][256];
int cond = 0;
//parse args until the end of the line
while (*shadersource)
{
@ -6313,7 +6441,7 @@ qboolean Shader_ReadShaderTerms(shader_t *s, char **shadersource, int parsemode,
}
}
body = shadermacros[i].body;
Shader_ReadShaderTerms(s, &body, parsemode, &cond, 0, &cond);
Shader_ReadShaderTerms(s, &body, parsemode, cond);
return true;
}
}
@ -6330,10 +6458,8 @@ qboolean Shader_ReadShaderTerms(shader_t *s, char **shadersource, int parsemode,
//loads a shader string into an existing shader object, and finalises it and stuff
static void Shader_ReadShader(shader_t *s, char *shadersource, int parsemode)
{
struct scondinfo_s cond = {0};
char *shaderstart = shadersource;
int conddepth = 0;
int cond[8];
cond[0] = 0;
memset(&parsestate, 0, sizeof(parsestate));
parsestate.mode = parsemode;
@ -6349,11 +6475,11 @@ static void Shader_ReadShader(shader_t *s, char *shadersource, int parsemode)
// set defaults
s->flags = SHADER_CULL_FRONT;
while (Shader_ReadShaderTerms(s, &shadersource, parsemode, &conddepth, sizeof(cond)/sizeof(cond[0]), cond))
while (Shader_ReadShaderTerms(s, &shadersource, parsemode, &cond))
{
}
if (conddepth)
if (cond.depth)
{
Con_Printf("if statements without endif in shader %s\n", s->name);
}
@ -6720,14 +6846,14 @@ char *Shader_Decompose(shader_t *s)
{
case SHADER_SORT_NONE: sprintf(o, "sort %i (SHADER_SORT_NONE)\n", s->sort); break;
case SHADER_SORT_RIPPLE: sprintf(o, "sort %i (SHADER_SORT_RIPPLE)\n", s->sort); break;
case SHADER_SORT_PRELIGHT: sprintf(o, "sort %i (SHADER_SORT_PRELIGHT)\n", s->sort); break;
case SHADER_SORT_DEFERREDLIGHT: sprintf(o, "sort %i (SHADER_SORT_DEFERREDLIGHT)\n", s->sort); break;
case SHADER_SORT_PORTAL: sprintf(o, "sort %i (SHADER_SORT_PORTAL)\n", s->sort); break;
case SHADER_SORT_SKY: sprintf(o, "sort %i (SHADER_SORT_SKY)\n", s->sort); break;
case SHADER_SORT_OPAQUE: sprintf(o, "sort %i (SHADER_SORT_OPAQUE)\n", s->sort); break;
case SHADER_SORT_DECAL: sprintf(o, "sort %i (SHADER_SORT_DECAL)\n", s->sort); break;
case SHADER_SORT_SEETHROUGH:sprintf(o, "sort %i (SHADER_SORT_SEETHROUGH)\n", s->sort); break;
case SHADER_SORT_SEETHROUGH: sprintf(o, "sort %i (SHADER_SORT_SEETHROUGH)\n", s->sort); break;
case SHADER_SORT_BANNER: sprintf(o, "sort %i (SHADER_SORT_BANNER)\n", s->sort); break;
case SHADER_SORT_UNDERWATER:sprintf(o, "sort %i (SHADER_SORT_UNDERWATER)\n", s->sort); break;
case SHADER_SORT_UNDERWATER: sprintf(o, "sort %i (SHADER_SORT_UNDERWATER)\n", s->sort); break;
case SHADER_SORT_BLEND: sprintf(o, "sort %i (SHADER_SORT_BLEND)\n", s->sort); break;
case SHADER_SORT_ADDITIVE: sprintf(o, "sort %i (SHADER_SORT_ADDITIVE)\n", s->sort); break;
case SHADER_SORT_NEAREST: sprintf(o, "sort %i (SHADER_SORT_NEAREST)\n", s->sort); break;

View file

@ -83,7 +83,7 @@ cvar_t r_sun_colour = CVARFD ("r_sun_colour", "0 0 0", CVAR_ARCHIVE, "Spec
static void Sh_DrawEntLighting(dlight_t *light, vec3_t colour);
static pvsbuffer_t lvisb;
static pvsbuffer_t lvisb, lvisb2;
/*
called on framebuffer resize.
@ -137,7 +137,8 @@ typedef struct shadowmesh_s
{
SMT_STENCILVOLUME, //build edges mesh (and surface list)
SMT_SHADOWMAP, //build front faces mesh (and surface list)
SMT_SHADOWLESS //build surface list only
SMT_SHADOWLESS, //build vis+surface list only
SMT_DEFERRED //build vis without caring about any surfaces at all.
} type;
unsigned int numindicies;
unsigned int maxindicies;
@ -638,6 +639,9 @@ static void SHM_RecursiveWorldNodeQ1_r (dlight_t *dl, mnode_t *node)
pleaf = (mleaf_t *)node;
SHM_Shadow_Cache_Leaf(pleaf);
if (sh_shmesh->type == SMT_DEFERRED) //such rtlights don't need ANY surface info, just a tight pvs
return;
mark = pleaf->firstmarksurface;
c = pleaf->nummarksurfaces;
@ -990,7 +994,7 @@ static void SHM_RecursiveWorldNodeQ2_r (dlight_t *dl, mnode_t *node)
SHM_RecursiveWorldNodeQ2_r (dl, node->children[!side]);
}
static void SHM_MarkLeavesQ2(dlight_t *dl, unsigned char *lvis, unsigned char *vvis)
static void SHM_MarkLeavesQ2(dlight_t *dl, unsigned char *lvis)
{
mnode_t *node;
int i;
@ -1007,7 +1011,7 @@ static void SHM_MarkLeavesQ2(dlight_t *dl, unsigned char *lvis, unsigned char *v
cluster = leaf->cluster;
if (cluster == -1)
continue;
if (lvis[cluster>>3] & (1<<(cluster&7)))// && vvis[cluster>>3] & (1<<(cluster&7)))
if (lvis[cluster>>3] & (1<<(cluster&7)))
{
node = (mnode_t *)leaf;
do
@ -1029,7 +1033,7 @@ static void SHM_MarkLeavesQ2(dlight_t *dl, unsigned char *lvis, unsigned char *v
cluster = leaf->cluster;
if (cluster == -1)
continue;
if (lvis[cluster>>3] & /*vvis[cluster>>3] &*/ (1<<(cluster&7)))
if (lvis[cluster>>3] & (1<<(cluster&7)))
{
node = (mnode_t *)leaf;
do
@ -1415,7 +1419,7 @@ static void SHM_ComposeVolume_BruteForce(dlight_t *dl)
}
#endif
static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvis, unsigned char *vvis, int type)
static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvis, int type)
{
float *v1, *v2;
vec3_t v3, v4;
@ -1426,8 +1430,17 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi
if (!lvis)
{
int clus;
// if ((type == SMT_SHADOWLESS || dl->lightcolourscales[0]) && cl.worldmodel->funcs.ClustersInSphere)
//shadowless lights don't cast shadows, so they're seen through everything - their vis must reflect that.
// lvis = cl.worldmodel->funcs.ClustersInSphere(cl.worldmodel, dl->origin, dl->radius, &lvisb, NULL);
// else
{
clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin);
lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST);
// if (cl.worldmodel->funcs.ClustersInSphere)
// lvis = cl.worldmodel->funcs.ClustersInSphere(cl.worldmodel, dl->origin, dl->radius, &lvisb2, lvis);
}
}
firstedge=0;
@ -1463,7 +1476,7 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi
#ifdef Q2BSPS
case fg_quake2:
SHM_BeginShadowMesh(dl, type);
SHM_MarkLeavesQ2(dl, lvis, vvis);
SHM_MarkLeavesQ2(dl, lvis);
SHM_RecursiveWorldNodeQ2_r(dl, cl.worldmodel->nodes);
break;
#endif
@ -2391,7 +2404,7 @@ qboolean Sh_GenShadowMap (dlight_t *l, vec3_t axis[3], qbyte *lvis, int smsize)
memcpy(oproj, r_refdef.m_projection, sizeof(oproj));
memcpy(oview, r_refdef.m_view, sizeof(oview));
oprect = r_refdef.pxrect;
smesh = SHM_BuildShadowMesh(l, lvis, NULL, SMT_SHADOWMAP);
smesh = SHM_BuildShadowMesh(l, lvis, SMT_SHADOWMAP);
Matrix4x4_CM_Projection_Far(r_refdef.m_projection, l->fov?l->fov:90, l->fov?l->fov:90, r_shadow_shadowmapping_nearclip.value, l->radius);
@ -2662,6 +2675,8 @@ static void Sh_DrawShadowMapLight(dlight_t *l, vec3_t colour, vec3_t axis[3], qb
clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, l->origin);
lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST);
//FIXME: surely we can use the phs for this?
// if (cl.worldmodel->funcs.ClustersInSphere)
// lvis = cl.worldmodel->funcs.ClustersInSphere(cl.worldmodel, l->origin, l->radius, &lvisb2, lvis);
if (!Sh_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect.
{
@ -2891,7 +2906,11 @@ static void Sh_DrawBrushModelShadow(dlight_t *dl, entity_t *e)
qglEnd();
}
#ifdef BEF_PUSHDEPTH
GLBE_PolyOffsetStencilShadow(false);
#else
GLBE_PolyOffsetStencilShadow();
#endif
}
#endif
@ -2909,7 +2928,7 @@ static void Sh_DrawStencilLightShadows(dlight_t *dl, qbyte *lvis, qbyte *vvis, q
model_t *emodel;
#endif
sm = SHM_BuildShadowMesh(dl, lvis, vvis, SMT_STENCILVOLUME);
sm = SHM_BuildShadowMesh(dl, lvis, SMT_STENCILVOLUME);
if (!sm)
{
#ifdef GLQUAKE
@ -3054,6 +3073,8 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, vec3_t axis[3],
{
clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin);
lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST);
// if (cl.worldmodel->funcs.ClustersInSphere)
// lvis = cl.worldmodel->funcs.ClustersInSphere(cl.worldmodel, dl->origin, dl->radius, &lvisb2, lvis);
if (!Sh_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect.
{
@ -3257,6 +3278,44 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, vec3_t axis[3],
#define Sh_DrawStencilLight Sh_DrawShadowlessLight
#endif
qboolean Sh_CullLight(dlight_t *dl, qbyte *vvis)
{
if (R_CullSphere(dl->origin, dl->radius))
{
RQuantAdd(RQUANT_RTLIGHT_CULL_FRUSTUM, 1);
return true; //this should be the more common case
}
if (!dl->rebuildcache)
{
//fixme: check head node first?
if (!Sh_LeafInView(dl->worldshadowmesh->litleaves, vvis))
{
RQuantAdd(RQUANT_RTLIGHT_CULL_PVS, 1);
return true;
}
}
else
{
int clus;
qbyte *lvis;
clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin);
lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST);
// if (cl.worldmodel->funcs.ClustersInSphere)
// lvis = cl.worldmodel->funcs.ClustersInSphere(cl.worldmodel, dl->origin, dl->radius, &lvisb2, lvis);
SHM_BuildShadowMesh(dl, lvis, SMT_DEFERRED);
if (!Sh_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect.
{
RQuantAdd(RQUANT_RTLIGHT_CULL_PVS, 1);
return true;
}
}
return false; //please draw this...
}
static void Sh_DrawShadowlessLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], qbyte *vvis)
{
vec3_t mins, maxs;
@ -3282,10 +3341,15 @@ static void Sh_DrawShadowlessLight(dlight_t *dl, vec3_t colour, vec3_t axis[3],
int clus;
qbyte *lvis;
if (cl.worldmodel->funcs.ClustersInSphere)
lvis = cl.worldmodel->funcs.ClustersInSphere(cl.worldmodel, dl->origin, dl->radius, &lvisb2, NULL);
else
{
clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin);
lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST);
}
SHM_BuildShadowMesh(dl, lvis, vvis, SMT_SHADOWLESS);
SHM_BuildShadowMesh(dl, lvis, SMT_SHADOWLESS);
if (!Sh_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect.
{
@ -3483,7 +3547,7 @@ void Sh_PreGenerateLights(void)
leaf = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin);
lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, leaf, &lvisb, PVM_FAST);
SHM_BuildShadowMesh(dl, lvis, NULL, shadowtype);
SHM_BuildShadowMesh(dl, lvis, shadowtype);
continue;
}
}

View file

@ -767,7 +767,18 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
if (GL_CheckExtension("GL_ARB_depth_clamp") || GL_CheckExtension("GL_NV_depth_clamp"))
gl_config.arb_depth_clamp = true;
if (GL_CheckExtension("GL_ARB_texture_compression"))
if (gl_config.gles)
{ //GL_ARB_texture_compression is not quite supported in gles, but works for custom compressed formats (like etc2).
qglCompressedTexImage2DARB = (void *)getglext("glCompressedTexImage2D");
qglGetCompressedTexImageARB = NULL;
}
else if (!gl_config.gles && gl_config.glversion > 1.3)
{ //GL_ARB_texture_compression is core in gl1.3
qglCompressedTexImage2DARB = (void *)getglext("glCompressedTexImage2D");
qglGetCompressedTexImageARB = (void *)getglext("glGetCompressedTexImage");
gl_config.arb_texture_compression = true;
}
else if (GL_CheckExtension("GL_ARB_texture_compression"))
{
qglCompressedTexImage2DARB = (void *)getglext("glCompressedTexImage2DARB");
qglGetCompressedTexImageARB = (void *)getglext("glGetCompressedTexImageARB");
@ -1667,7 +1678,7 @@ static const char *glsl_hdrs[] =
"sys/pcf.h",
//!!cvardf r_glsl_pcf
"#ifndef PCF\n"
"#define ShadowmapFilter(smap) 1.0\n" //s_shadowmap generally. returns a scaler to say how much light should be used for this pixel.
"#define ShadowmapFilter(smap,proj) 1.0\n" //s_shadowmap generally. returns a scaler to say how much light should be used for this pixel.
"#else\n"
"#ifndef r_glsl_pcf\n"
"#define r_glsl_pcf 9\n"
@ -1680,12 +1691,12 @@ static const char *glsl_hdrs[] =
"uniform vec4 l_shadowmapproj;\n" //light projection matrix info
"uniform vec2 l_shadowmapscale;\n" //xy are the texture scale, z is 1, w is the scale.
"#endif\n"
"vec3 ShadowmapCoord(void)\n"
"vec3 ShadowmapCoord(vec4 cubeproj)\n"
"{\n"
"#ifdef SPOT\n"
//bias it. don't bother figuring out which side or anything, its not needed
//l_projmatrix contains the light's projection matrix so no other magic needed
"return ((vtexprojcoord.xyz-vec3(0.0,0.0,0.015))/vtexprojcoord.w + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5);\n"
"return ((cubeproj.xyz-vec3(0.0,0.0,0.015))/cubeproj.w + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5);\n"
//"#elif defined(CUBESHADOW)\n"
// vec3 shadowcoord = vshadowcoord.xyz / vshadowcoord.w;
// #define dosamp(x,y) shadowCube(s_t4, shadowcoord + vec2(x,y)*texscale.xy).r
@ -1694,21 +1705,21 @@ static const char *glsl_hdrs[] =
//texture is arranged thusly:
//forward left up
//back right down
"vec3 dir = abs(vtexprojcoord.xyz);\n"
"vec3 dir = abs(cubeproj.xyz);\n"
//assume z is the major axis (ie: forward from the light)
"vec3 t = vtexprojcoord.xyz;\n"
"vec3 t = cubeproj.xyz;\n"
"float ma = dir.z;\n"
"vec3 axis = vec3(0.5/3.0, 0.5/2.0, 0.5);\n"
"if (dir.x > ma)\n"
"{\n"
"ma = dir.x;\n"
"t = vtexprojcoord.zyx;\n"
"t = cubeproj.zyx;\n"
"axis.x = 0.5;\n"
"}\n"
"if (dir.y > ma)\n"
"{\n"
"ma = dir.y;\n"
"t = vtexprojcoord.xzy;\n"
"t = cubeproj.xzy;\n"
"axis.x = 2.5/3.0;\n"
"}\n"
//if the axis is negative, flip it.
@ -1727,9 +1738,9 @@ static const char *glsl_hdrs[] =
"#endif\n"
"}\n"
"float ShadowmapFilter(sampler2DShadow smap)\n"
"float ShadowmapFilter(sampler2DShadow smap, vec4 cubeproj)\n"
"{\n"
"vec3 shadowcoord = ShadowmapCoord();\n"
"vec3 shadowcoord = ShadowmapCoord(cubeproj);\n"
"#if 0\n"//def GL_ARB_texture_gather
"vec2 ipart, fpart;\n"
@ -1951,8 +1962,29 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
"#define textureCube texture\n"
"#define shadow2D texture\n"
//gl_FragColor and gl_FragData got deprecated too, need to make manual outputs
"out vec4 fte_fragdata;\n"
"#define gl_FragColor fte_fragdata\n"
"#if __VERSION__ >= 300\n" //gl3.3, gles3 (gles3 requires layout stuff)
"layout(location = 0) out vec4 fte_fragdata0;"
"layout(location = 1) out vec4 fte_fragdata1;"
"layout(location = 2) out vec4 fte_fragdata2;"
"layout(location = 3) out vec4 fte_fragdata3;"
"\n#else\n"
"out vec4 fte_fragdata0;"
"out vec4 fte_fragdata1;"
"out vec4 fte_fragdata2;"
"out vec4 fte_fragdata3;"
"\n#endif\n" //gles3 requires this
"#define gl_FragColor fte_fragdata0\n"
;
length[strings] = strlen(prstrings[strings]);
strings++;
}
else
{
prstrings[strings] =
"#define fte_fragdata0 gl_FragData[0]\n"
"#define fte_fragdata1 gl_FragData[1]\n"
"#define fte_fragdata2 gl_FragData[2]\n"
"#define fte_fragdata3 gl_FragData[3]\n"
;
length[strings] = strlen(prstrings[strings]);
strings++;
@ -2200,7 +2232,7 @@ static GLhandleARB GLSlang_FinishShader(GLhandleARB shader, const char *name, GL
Sys_Error("%s shader (%s) compilation error:\n----------\n%s----------\n", typedesc, name, str);
if (developer.ival)
{
{ //could use echo console-link I guess (with embedded line numbers). shaders can get quite big though.
unsigned int line;
char *eol, *start;
qglGetShaderSource(shader, sizeof(str), NULL, str);
@ -2857,6 +2889,7 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name))
#endif
{ //gles3 and gl4.3 have mandatory support for etc2. probably desktop drivers will pre-decompress, but whatever.
//webgl tries to cater to d3d, so doesn't support this gles3 feature, because browser writers are lazy.
//warning: while support is mandatory, it may just be a driver trick with the hardware using uncompressed data.
sh_config.texfmt[PTI_ETC1_RGB8] = true;
sh_config.texfmt[PTI_ETC2_RGB8] = true;
sh_config.texfmt[PTI_ETC2_RGB8A1] = true;

View file

@ -2282,7 +2282,8 @@ static qboolean XCursor_Init(void)
};
qboolean defaulthwcursor = true;
if (!strcmp(gl_vendor, "Humper") && !strcmp(gl_renderer, "Chromium"))
#ifdef GLQUAKE
if (qrenderer == QR_OPENGL && !strcmp(gl_vendor, "Humper") && !strcmp(gl_renderer, "Chromium"))
{ //I don't really understand the significance of these two values, but we get them when running inside VirtualBox
//in such cases, the opengl window has a nasty habit of appearing top-most, even above mouse cursors...
//so we NEED to disable hardware cursors by default in this case, because otherwise we won't see any
@ -2290,6 +2291,7 @@ static qboolean XCursor_Init(void)
Con_Printf("VirtualBox Detected: OpenGL obscures hardware cursors. seta x11_allow_xcursor 1 to ignore.\n");
defaulthwcursor = false;
}
#endif
//in case they were previously set...
rf->VID_CreateCursor = NULL;

View file

@ -135,8 +135,9 @@ qboolean R_DrawSkyChain (batch_t *batch)
{
skyshader = forcedsky;
if (forcedsky->numpasses)
if (forcedsky->numpasses && !forcedsky->skydome)
{ //cubemap skies!
//this is just a simple pass. we use glsl/texgen for any actual work
batch_t b = *batch;
b.shader = forcedsky;
b.skin = NULL;
@ -158,7 +159,7 @@ qboolean R_DrawSkyChain (batch_t *batch)
skyboxtex = NULL;
if (skyboxtex && TEXVALID(*skyboxtex))
{
{ //draw a skybox if we were given the textures
R_CalcSkyChainBounds(batch);
GL_DrawSkyBox (skyboxtex, batch);
@ -166,20 +167,22 @@ qboolean R_DrawSkyChain (batch_t *batch)
GL_DrawSkySphere(batch, skyshader);
}
else if (skyshader->numpasses)
{
{ //if we have passes, then they're normally projected.
if (*r_fastsky.string && TEXVALID(batch->shader->defaulttextures->base) && TEXVALID(batch->shader->defaulttextures->fullbright))
{
{ //we have a small perf trick to accelerate q1 skies, also helps avoids distortions, but doesn't work too well for any other type of sky.
R_CalcSkyChainBounds(batch);
GL_DrawSkyGrid(skyshader->defaulttextures);
}
else
GL_DrawSkySphere(batch, skyshader);
}
/*else if (batch->meshes)
{ //if you had wanted it invisible, you should have used nodraw.
else if (batch->meshes)
{ //skys are weird.
//they're the one type of surface with implicit nodraw when there's no passes.
if (batch->shader->skydome || batch->shader->numpasses)
R_DrawFastSky(batch);
return true; //depth will always be drawn with this pathway.
}*/
return true; //depth will always be drawn with this pathway... or we were not drawing anything anyway...
}
//neither skydomes nor skyboxes nor skygrids will have been drawn with the correct depth values for the sky.
//this can result in rooms behind the sky surfaces being visible.

View file

@ -8340,7 +8340,9 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_OPENGL, 110, "lpp_depthnorm",
"!!permu BUMP\n"
"!!permu SKELETAL\n"
"!!permu FRAMEBLEND\n"
"!!cvarf r_glsl_offsetmapping_scale\n"
"!!samps normalmap specular\n"
//light pre-pass rendering (defered lighting)
//this is the initial pass, that draws the surface normals and depth to the initial colour buffer
@ -8351,8 +8353,11 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"varying vec3 eyevector;\n"
"#endif\n"
"varying vec3 norm, tang, bitang;\n"
"varying vec3 norm;\n"
"#if defined(BUMP)\n"
"varying vec3 tang, bitang;\n"
"#endif\n"
"#if defined(BUMP) || defined(SPECULAR)\n"
"varying vec2 tc;\n"
"#endif\n"
"#ifdef VERTEX_SHADER\n"
@ -8362,10 +8367,12 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"{\n"
"#if defined(BUMP)\n"
"gl_Position = skeletaltransform_nst(norm, tang, bitang);\n"
"tc = v_texcoord;\n"
"#else\n"
"gl_Position = skeletaltransform_n(norm);\n"
"#endif\n"
"#if defined(BUMP) || defined(SPECULAR)\n"
"tc = v_texcoord;\n"
"#endif\n"
"#if defined(OFFSETMAPPING)\n"
"vec3 eyeminusvertex = e_eyepos - v_position.xyz;\n"
@ -8388,13 +8395,24 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"#endif\n"
"vec3 onorm;\n"
"vec4 ospec;\n"
//need to write surface normals so that light shines on the surfaces properly
"#if defined(BUMP)\n"
"vec3 bm = 2.0*texture2D(s_normalmap, tc).xyz - 1.0;\n"
"onorm = normalize(bm.x * tang + bm.y * bitang + bm.z * norm);\n"
"#else\n"
"onorm = norm;\n"
"#endif\n"
"gl_FragColor = vec4(onorm.xyz, gl_FragCoord.z);\n"
//we need to write specular exponents if we want per-pixel control over that
//#if defined(SPECULAR)
"ospec = texture2D(s_specular, tc);\n"
//#else
// ospec = vec4(0.0, 0.0, 0.0, 0.0);
//#endif
"gl_FragColor = vec4(onorm.xyz, ospec.a * FTE_SPECULAR_EXPONENT);\n"
"}\n"
"#endif\n"
},
@ -8404,9 +8422,17 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
//this shader is a light shader. ideally drawn with a quad covering the entire region
//the output is contribution from this light (which will be additively blended)
//you can blame Electro for much of the maths in here.
//fixme: no fog
"!!ver 100 450\n"
//FIXME: !!permu FOG
"!!samps shadowmap 2\n"
//s_t0 is the normals and depth
"#define USE_ARB_SHADOW\n"
"#include \"sys/defs.h\"\n"
"#include \"sys/pcf.h\"\n"
//s_t0 is the depth
//s_t1 is the normals+spec-exponent
//output should be amount of light hitting the surface.
"varying vec4 tf;\n"
@ -8418,136 +8444,9 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0; //norm.xyz, depth\n"
"uniform vec3 l_lightposition;\n"
"uniform mat4 m_invviewprojection;\n"
"uniform vec3 l_lightcolour;\n"
"uniform float l_lightradius;\n"
"uniform mat4 l_cubematrix;\n"
"#ifdef PCF\n"
"#define USE_ARB_SHADOW\n"
"#ifndef USE_ARB_SHADOW\n"
//fall back on regular samplers if we must
"#define sampler2DShadow sampler2D\n"
"#endif\n"
"uniform sampler2DShadow s_shadowmap;\n"
//FIXME: shadowmaps need to be atlased!
"uniform vec4 l_shadowmapproj; //light projection matrix info\n"
"uniform vec2 l_shadowmapscale; //xy are the texture scale, z is 1, w is the scale.\n"
"vec3 ShadowmapCoord(vec4 cubeproj)\n"
"{\n"
"#ifdef SPOT\n"
//bias it. don't bother figuring out which side or anything, its not needed
//l_projmatrix contains the light's projection matrix so no other magic needed
"return ((cubeproj.xyz-vec3(0.0,0.0,0.015))/cubeproj.w + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5);\n"
//#elif defined(CUBESHADOW)
// vec3 shadowcoord = vshadowcoord.xyz / vshadowcoord.w;
// #define dosamp(x,y) shadowCube(s_shadowmap, shadowcoord + vec2(x,y)*texscale.xy).r
"#else\n"
//figure out which axis to use
//texture is arranged thusly:
//forward left up
//back right down
"vec3 dir = abs(cubeproj.xyz);\n"
//assume z is the major axis (ie: forward from the light)
"vec3 t = cubeproj.xyz;\n"
"float ma = dir.z;\n"
"vec3 axis = vec3(0.5/3.0, 0.5/2.0, 0.5);\n"
"if (dir.x > ma)\n"
"{\n"
"ma = dir.x;\n"
"t = cubeproj.zyx;\n"
"axis.x = 0.5;\n"
"}\n"
"if (dir.y > ma)\n"
"{\n"
"ma = dir.y;\n"
"t = cubeproj.xzy;\n"
"axis.x = 2.5/3.0;\n"
"}\n"
//if the axis is negative, flip it.
"if (t.z > 0.0)\n"
"{\n"
"axis.y = 1.5/2.0;\n"
"t.z = -t.z;\n"
"}\n"
//we also need to pass the result through the light's projection matrix too
//the 'matrix' we need only contains 5 actual values. and one of them is a -1. So we might as well just use a vec4.
//note: the projection matrix also includes scalers to pinch the image inwards to avoid sampling over borders, as well as to cope with non-square source image
//the resulting z is prescaled to result in a value between -0.5 and 0.5.
//also make sure we're in the right quadrant type thing
"return axis + ((l_shadowmapproj.xyz*t.xyz + vec3(0.0, 0.0, l_shadowmapproj.w)) / -t.z);\n"
"#endif\n"
"}\n"
"float ShadowmapFilter(vec4 vtexprojcoord)\n"
"{\n"
"vec3 shadowcoord = ShadowmapCoord(vtexprojcoord);\n"
"#if 0//def GL_ARB_texture_gather\n"
"vec2 ipart, fpart;\n"
"#define dosamp(x,y) textureGatherOffset(s_shadowmap, ipart.xy, vec2(x,y)))\n"
"vec4 tl = step(shadowcoord.z, dosamp(-1.0, -1.0));\n"
"vec4 bl = step(shadowcoord.z, dosamp(-1.0, 1.0));\n"
"vec4 tr = step(shadowcoord.z, dosamp(1.0, -1.0));\n"
"vec4 br = step(shadowcoord.z, dosamp(1.0, 1.0));\n"
//we now have 4*4 results, woo
//we can just average them for 1/16th precision, but that's still limited graduations
//the middle four pixels are 'full strength', but we interpolate the sides to effectively give 3*3
"vec4 col = vec4(tl.ba, tr.ba) + vec4(bl.rg, br.rg) + //middle two rows are full strength\n"
"mix(vec4(tl.rg, tr.rg), vec4(bl.ba, br.ba), fpart.y); //top+bottom rows\n"
"return dot(mix(col.rgb, col.agb, fpart.x), vec3(1.0/9.0)); //blend r+a, gb are mixed because its pretty much free and gives a nicer dot instruction instead of lots of adds.\n"
"#else\n"
"#ifdef USE_ARB_SHADOW\n"
//with arb_shadow, we can benefit from hardware acclerated pcf, for smoother shadows
"#define dosamp(x,y) shadow2D(s_shadowmap, shadowcoord.xyz + (vec3(x,y,0.0)*l_shadowmapscale.xyx)).r\n"
"#else\n"
//this will probably be a bit blocky.
"#define dosamp(x,y) float(texture2D(s_shadowmap, shadowcoord.xy + (vec2(x,y)*l_shadowmapscale.xy)).r >= shadowcoord.z)\n"
"#endif\n"
"float s = 0.0;\n"
"#if r_glsl_pcf >= 1 && r_glsl_pcf < 5\n"
"s += dosamp(0.0, 0.0);\n"
"return s;\n"
"#elif r_glsl_pcf >= 5 && r_glsl_pcf < 9\n"
"s += dosamp(-1.0, 0.0);\n"
"s += dosamp(0.0, -1.0);\n"
"s += dosamp(0.0, 0.0);\n"
"s += dosamp(0.0, 1.0);\n"
"s += dosamp(1.0, 0.0);\n"
"return s/5.0;\n"
"#else\n"
"s += dosamp(-1.0, -1.0);\n"
"s += dosamp(-1.0, 0.0);\n"
"s += dosamp(-1.0, 1.0);\n"
"s += dosamp(0.0, -1.0);\n"
"s += dosamp(0.0, 0.0);\n"
"s += dosamp(0.0, 1.0);\n"
"s += dosamp(1.0, -1.0);\n"
"s += dosamp(1.0, 0.0);\n"
"s += dosamp(1.0, 1.0);\n"
"return s/9.0;\n"
"#endif\n"
"#endif\n"
"}\n"
"#else\n"
"float ShadowmapFilter(vec4 vtexprojcoord)\n"
"{\n"
"return 1.0;\n"
"}\n"
"#endif\n"
"#define out_diff fte_fragdata0\n"
"#define out_spec fte_fragdata1\n"
"vec3 calcLightWorldPos(vec2 screenPos, float depth)\n"
"{\n"
@ -8557,16 +8456,13 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"void main ()\n"
"{\n"
"vec3 lightColour = l_lightcolour.rgb;\n"
"float lightIntensity = 1.0;\n"
"float lightAttenuation = l_lightradius; // fixme: just use the light radius for now, use better near/far att math separately once working\n"
"float radiusFar = l_lightradius;\n"
"float radiusNear = l_lightradius*0.5;\n"
"vec2 fc;\n"
"fc = tf.xy / tf.w;\n"
"vec4 data = texture2D(s_t0, (1.0 + fc) / 2.0);\n"
"float depth = data.a;\n"
"vec2 fc = tf.xy / tf.w;\n"
"vec2 gc = (1.0 + fc) / 2.0;\n"
"float depth = texture2D(s_t0, gc).r;\n"
"vec4 data = texture2D(s_t1, gc);\n"
"vec3 norm = data.xyz;\n"
"float spec_exponent = data.a;\n"
/* calc where the wall that generated this sample came from */
"vec3 worldPos = calcLightWorldPos(fc, depth);\n"
@ -8574,23 +8470,27 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
/*we need to know the cube projection (for both cubemaps+shadows)*/
"vec4 cubeaxis = l_cubematrix*vec4(worldPos.xyz, 1.0);\n"
/*calc diffuse lighting term*/
/*calc ambient lighting term*/
"vec3 lightDir = l_lightposition - worldPos;\n"
"float zdiff = 1.0 - clamp(length(lightDir) / lightAttenuation, 0.0, 1.0);\n"
"float atten = (radiusFar * zdiff) / (radiusFar - radiusNear);\n"
"atten = pow(atten, 2.0);\n"
"float atten = max(1.0 - (dot(lightDir, lightDir)/(l_lightradius*l_lightradius)), 0.0);\n"
/*calc diffuse lighting term*/
"lightDir = normalize(lightDir);\n"
"float nDotL = dot(norm, lightDir);\n"
"float lightDiffuse = max(0.0, nDotL) * atten;\n"
"float lightDiffuse = max(0.0, nDotL);\n"
/*calc specular term*/
//fixme
/*calc specular lighting term*/
"vec3 halfdir = normalize(normalize(e_eyepos - worldPos) + lightDir); //ASSUMPTION: e_eyepos requires an identity modelmatrix (true for world+sprites, but usually not for models/bsps)\n"
"float spec = pow(max(dot(halfdir, norm), 0.0), spec_exponent);\n"
//fixme: apply fog
//fixme: output a specular term
//fixme: apply fog?
//fixme: cubemap filters
"gl_FragColor = vec4(lightDiffuse * (lightColour * lightIntensity) * ShadowmapFilter(cubeaxis), 1.0);\n"
"float shadows = ShadowmapFilter(s_shadowmap, cubeaxis);\n"
"lightColour *= atten;\n"
"out_diff = vec4(lightColour * (l_lightcolourscale.x + l_lightcolourscale.y*lightDiffuse*shadows), 1.0);\n"
"out_spec = vec4(lightColour * l_lightcolourscale.z*spec*shadows, 1.0);\n"
"}\n"
"#endif\n"
},
@ -8599,6 +8499,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
{QR_OPENGL, 110, "lpp_wall",
"!!permu BUMP //for offsetmapping rather than bumpmapping (real bumps are handled elsewhere)\n"
"!!cvarf r_glsl_offsetmapping_scale\n"
"!!samps 2\n"
//the final defered lighting pass.
//the lighting values were written to some render target, which is fed into this shader, and now we draw all the wall textures with it.
@ -8628,7 +8529,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"uniform sampler2D s_t0; //light gbuffer\n"
"#ifdef OFFSETMAPPING\n"
"#include \"sys/offsetmapping.h\"\n"
"#endif\n"
@ -8643,16 +8543,19 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"vec2 nst;\n"
"nst = tf.xy / tf.w;\n"
"nst = (1.0 + nst) / 2.0;\n"
"vec4 l = texture2D(s_t0, nst);\n"
"vec4 dl = texture2D(s_t0, nst); //diffuse lighting\n"
"vec4 sl = texture2D(s_t1, nst); //specular lighting\n"
"vec4 c = texture2D(s_diffuse, tc);\n"
"vec4 s = texture2D(s_specular, tc);\n"
"vec4 f = texture2D(s_fullbright, tc);\n"
//fixme: top+bottom should add upper+lower colours to c here
"vec3 lmsamp = texture2D(s_lightmap, lm).rgb*e_lmscale.rgb;\n"
//fixme: fog the legacy lightmap data
"vec3 diff = l.rgb;\n"
// vec3 chrom = diff / (0.001 + dot(diff, vec3(0.3, 0.59, 0.11)));
// vec3 spec = chrom * l.a;
"vec3 diff = dl.rgb + lmsamp;\n"
"vec3 spec = sl.rgb * float(SPECMUL); //should be rgb, but whatever.\n"
//fixme: do specular somehow
"gl_FragColor = vec4((diff + lmsamp) * c.xyz, 1.0);\n"
"gl_FragColor = vec4(diff*c.rgb + spec*s.rgb + f.rgb, 1.0);\n"
//fixme: fullbrights should add to the rgb value
"}\n"
"#endif\n"
@ -11077,7 +10980,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"float colorscale = max(1.0 - (dot(lightvector, lightvector)/(l_lightradius*l_lightradius)), 0.0);\n"
"#ifdef PCF\n"
/*filter the light by the shadowmap. logically a boolean, but we allow fractions for softer shadows*/
"colorscale *= ShadowmapFilter(s_shadowmap);\n"
"colorscale *= ShadowmapFilter(s_shadowmap, vtexprojcoord);\n"
"#endif\n"
"#if defined(SPOT)\n"
/*filter the colour by the spotlight. discard anything behind the light so we don't get a mirror image*/

View file

@ -279,7 +279,18 @@ typedef struct shaderpass_s {
T_GEN_VIDEOMAP, //use the media playback as an image source, updating each frame for which it is visible
T_GEN_CUBEMAP, //use a cubemap instead, otherwise like T_GEN_SINGLEMAP
T_GEN_3DMAP //use a 3d texture instead, otherwise T_GEN_SINGLEMAP.
T_GEN_3DMAP, //use a 3d texture instead, otherwise T_GEN_SINGLEMAP.
#define GBUFFER_COUNT 8
#define T_GEN_GBUFFERCASE T_GEN_GBUFFER0:case T_GEN_GBUFFER1:case T_GEN_GBUFFER2:case T_GEN_GBUFFER3:case T_GEN_GBUFFER4:case T_GEN_GBUFFER5:case T_GEN_GBUFFER6:case T_GEN_GBUFFER7
T_GEN_GBUFFER0, //one of the gbuffer images (deferred lighting).
T_GEN_GBUFFER1, //one of the gbuffer images (deferred lighting).
T_GEN_GBUFFER2, //one of the gbuffer images (deferred lighting).
T_GEN_GBUFFER3, //one of the gbuffer images (deferred lighting).
T_GEN_GBUFFER4, //one of the gbuffer images (deferred lighting).
T_GEN_GBUFFER5, //one of the gbuffer images (deferred lighting).
T_GEN_GBUFFER6, //one of the gbuffer images (deferred lighting).
T_GEN_GBUFFER7, //one of the gbuffer images (deferred lighting).
} texgen;
enum {
@ -683,12 +694,12 @@ void Shader_ReleaseGeneric(program_t *prog);
mfog_t *Mod_FogForOrigin(model_t *wmodel, vec3_t org);
#ifndef NOLEGACY
#define BEF_FORCEDEPTHWRITE 1
#define BEF_FORCEDEPTHTEST 2
#define BEF_FORCEADDITIVE 4 //blend dest = GL_ONE
#define BEF_FORCETRANSPARENT 8 //texenv replace -> modulate
#define BEF_FORCENODEPTH 16 //disables any and all depth.
#ifndef NOLEGACY
#define BEF_PUSHDEPTH 32 //additional polygon offset
#endif
//FIXME: the above should really be legacy-only

View file

@ -835,7 +835,7 @@ char *DecompileAgressiveType(dfunction_t *df, dstatement_t *last, gofs_t ofs)
{
if (last->c == ofs &&
pr_opcodes[last->op].associative == ASSOC_LEFT &&
pr_opcodes[last->op].priority_>0)
pr_opcodes[last->op].priorityclass)
{
//previous was an operation into the temp
return type_names[(*pr_opcodes[last->op].type_c)->type];
@ -1452,13 +1452,13 @@ char *DecompileImmediate_Get(dfunction_t *df, gofs_t ofs, QCC_type_t *req_t)
break;
case ev_entity:
if (!pr_globals[ofs])
QC_snprintfz(temp, sizeof(temp), "__NULL__/*entity*/");
QC_snprintfz(temp, sizeof(temp), "((entity)__NULL__)");
else
QC_snprintfz(temp, sizeof(temp), "(entity)%i", ((int*)pr_globals)[ofs]);
break;
case ev_field:
if (!pr_globals[ofs])
QC_snprintfz(temp, sizeof(temp), "__NULL__/*field*/");
QC_snprintfz(temp, sizeof(temp), "((.void)__NULL__)");
else
QC_snprintfz(temp, sizeof(temp), "/*field %s*/%i", DecompileGetFieldNameIdxByFinalOffset(((int*)pr_globals)[ofs]), ((int*)pr_globals)[ofs]);
break;
@ -2269,6 +2269,12 @@ char *DecompileValueString(etype_t type, void *val)
case ev_pointer:
QC_snprintfz(line, sizeof(line), "(__variant*)0x%xi", *(int *)val);
break;
case ev_function:
if (*(int *)val>0 && *(int *)val<numfunctions)
QC_snprintfz(line, sizeof(line), "(/*func 0x%x*/%s)", *(int *)val, strings+functions[*(int *)val].s_name);
else
QC_snprintfz(line, sizeof(line), "((void())0x%xi)", *(int *)val);
break;
default:
QC_snprintfz(line, sizeof(line), "bad type %i", type);
break;
@ -2980,6 +2986,13 @@ void DecompileProgsDat(char *name, void *buf, size_t bufsize)
if (c)
printf("Copyright: %s\n", c);
PreCompile();
pHash_Get = &Hash_Get;
pHash_GetNext = &Hash_GetNext;
pHash_Add = &Hash_Add;
pHash_RemoveData = &Hash_RemoveData;
Hash_InitTable(&typedeftable, 1024, qccHunkAlloc(Hash_BytesForBuckets(1024)));
maxtypeinfos = 64;
qcc_typeinfo = (void *)malloc(sizeof(QCC_type_t)*maxtypeinfos);
numtypeinfos = 0;

View file

@ -186,7 +186,7 @@ typedef struct
int targetflags; //weather we need to mark the progs as a newer version
char *name;
char *opname;
int priority_; //FIXME: priority should be done differently...
int priorityclass;
enum {ASSOC_LEFT, ASSOC_RIGHT, ASSOC_RIGHT_RESULT} associative;
struct QCC_type_s **type_a, **type_b, **type_c;

View file

@ -29,6 +29,17 @@ extern progfuncs_t *qccprogfuncs;
#define strnicmp strncasecmp
#endif
#ifdef _MSC_VER //ffs
#define strtoull _strtoui64
#ifndef PRIxPTR
#define PRIxPTR "Ix"
#endif
#else
#ifndef PRIxPTR
#define PRIxPTR "Ix"
#endif
#endif
void *qccHunkAlloc(size_t mem);
void qccClearHunk(void);
@ -279,7 +290,7 @@ There are no ++ / -- operators, or operate/assign operators.
#if 1
#include "hash.h"
extern hashtable_t compconstantstable;
extern hashtable_t globalstable, localstable;
extern hashtable_t globalstable, localstable, typedeftable;
#endif
#ifdef WRITEASM
@ -616,7 +627,10 @@ extern pbool flag_qccx;
extern pbool flag_attributes;
extern pbool flag_assumevar;
extern pbool flag_dblstarexp;
extern pbool flag_allowuninit;
extern pbool flag_cpriority;
extern pbool flag_embedsrc;
extern pbool flag_nopragmafileline;
extern pbool opt_overlaptemps;
extern pbool opt_shortenifnots;
@ -684,6 +698,7 @@ CompilerConstant_t *QCC_PR_DefineName(char *name);
const char *QCC_VarAtOffset(QCC_sref_t ref);
void QCC_PrioritiseOpcodes(void);
int QCC_PR_IntConstExpr(void);
#ifndef COMMONINLINES
@ -711,6 +726,7 @@ char *QCC_NameForWarning(int idx);
enum {
WARN_DEBUGGING,
WARN_ERROR,
WARN_DEPRECATEDWARNING, //to silence warnings about old warnings.
WARN_WRITTENNOTREAD,
WARN_READNOTWRITTEN,
WARN_NOTREFERENCED,

File diff suppressed because it is too large Load diff

View file

@ -1046,6 +1046,7 @@ pbool QCC_PR_Precompiler(void)
msg[a] = '\0';
strcpy(qcc_token, msg);
a=0;
if (*pr_file_p != '(')
continue;
}
msg[a++] = *pr_file_p;
@ -1113,10 +1114,39 @@ pbool QCC_PR_Precompiler(void)
qccincludeonced = onced;
}
else if (!QC_strcasecmp(qcc_token, "file"))
{ //#pragma file(foobar.qc)
if (!flag_nopragmafileline)
{
char *e;
char *m = msg;
if (*m == '(')
{
m++;
e = strchr(m, ')');
if (e)
*e = 0;
}
s_filen = e = qccHunkAlloc(strlen(m)+1);
strcpy(e, m);
if (opt_filenames)
{
optres_filenames += strlen(m);
s_filed = 0;
}
else
s_filed = QCC_CopyString (m);
}
}
else if (!QC_strcasecmp(qcc_token, "line"))
{ //#pragma line(666)
if (!flag_nopragmafileline)
{
char *m = msg;
if (*m == '(')
m++;
pr_source_line = strtoul(m, &m, 0)-1;
}
}
else if (!QC_strcasecmp(qcc_token, "includedir"))
{
@ -1323,7 +1353,11 @@ pbool QCC_PR_Precompiler(void)
if (!QC_strcasecmp(compiler_flag[f].abbrev, qcc_token))
{
if (compiler_flag[f].flags & FLAG_MIDCOMPILE)
{
*compiler_flag[f].enabled = st;
if (compiler_flag[f].enabled == &flag_cpriority)
QCC_PrioritiseOpcodes();
}
else
QCC_PR_ParseWarning(WARN_BADPRAGMA, "Cannot enable/disable keyword/flag via a pragma");
break;
@ -2244,7 +2278,7 @@ void QCC_PR_LexPunctuation (void)
if (pr_file_p[0] == '*' && pr_file_p[1] == '*' && flag_dblstarexp)
{ //for compat with gmqcc. fteqcc uses *^ internally (which does not conflict with multiplying by dereferenced pointers - sucks for MSCLR c++ syntax)
QCC_PR_ParseWarning(WARN_GMQCC_SPECIFIC, "** operator conflicts with pointers. Consider using *^ instead.", pr_token);
QCC_PR_ParseWarning(WARN_GMQCC_SPECIFIC, "** is unsafe around pointers, use *^ instead.", pr_token);
strcpy (pr_token, "*^");
pr_file_p += 2;
return;
@ -3097,22 +3131,35 @@ static void QCC_PR_ExpandStrCatMarkup(char **buffer, size_t *bufferlen, size_t *
/*no null terminator, remember to cat one if required*/
}
const struct tm *QCC_CurrentTime(void)
{
//if SOURCE_DATE_EPOCH environment is defined, use that as seconds from epoch (and show utc)
//this helps give reproducable builds (which is for some debian project, demonstrating that noone is hacking binaries).
const char *env = getenv("SOURCE_DATE_EPOCH");
time_t t;
if (env && *env)
{
t = strtoull(env, NULL, 0);
if (t)
return gmtime(&t);
}
t = time(NULL);
return localtime(&t);
}
static char *QCC_PR_CheckBuiltinCompConst(char *constname, char *retbuf, size_t retbufsize)
{
if (constname[0] != '_' || constname[1] != '_')
return NULL;
if (!strcmp(constname, "__TIME__"))
{
time_t long_time;
time( &long_time );
strftime( retbuf, retbufsize, "\"%H:%M\"", localtime( &long_time ));
strftime( retbuf, retbufsize, "\"%H:%M\"", QCC_CurrentTime());
return retbuf;
}
if (!strcmp(constname, "__DATE__"))
{
time_t long_time;
time( &long_time );
strftime( retbuf, retbufsize, "\"%a %d %b %Y\"", localtime( &long_time ));
strftime( retbuf, retbufsize, "\"%a %d %b %Y\"", QCC_CurrentTime());
return retbuf;
}
if (!strcmp(constname, "__RAND__"))
@ -3122,6 +3169,10 @@ static char *QCC_PR_CheckBuiltinCompConst(char *constname, char *retbuf, size_t
}
if (!strcmp(constname, "__QCCVER__"))
{
#ifdef SVNVERSION
if (strcmp(SVNVERSION, "-"))
return "FTEQCC " STRINGIFY(SVNVERSION);
#endif
return "\"FTEQCC "__DATE__","__TIME__"\"";
}
if (!strcmp(constname, "__FILE__"))
@ -4574,6 +4625,8 @@ QCC_type_t *QCC_PR_NextSubType(QCC_type_t *type, QCC_type_t *prev)
QCC_type_t *QCC_TypeForName(char *name)
{
return pHash_Get(&typedeftable, name);
/*
int i;
for (i = 0; i < numtypeinfos; i++)
@ -4584,7 +4637,7 @@ QCC_type_t *QCC_TypeForName(char *name)
}
}
return NULL;
return NULL;*/
}
/*
@ -4698,6 +4751,12 @@ QCC_type_t *QCC_PR_ParseFunctionType (int newtype, QCC_type_t *returntype)
if (paramlist[numparms].type->type == ev_void)
break; //float(void) has no actual args
if (!foundinout && QCC_PR_CheckToken("&"))
{ //accept c++ syntax, at least on arguments. its not quite the same, but it'll do.
paramlist[numparms].out = true;
foundinout = true;
}
// type->name = "FUNC PARAMETER";
paramlist[numparms].paramname = "";
@ -4985,18 +5044,9 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
strcpy(accessorname, funcname);
/* Look to see if this type is already defined */
for(i=0;i<numtypeinfos;i++)
{
if (!qcc_typeinfo[i].typedefed)
continue;
if (STRCMP(qcc_typeinfo[i].name, accessorname) == 0)
{
if (qcc_typeinfo[i].type != ev_accessor)
newt = QCC_TypeForName(accessorname);
if (newt && newt->type != ev_accessor)
QCC_PR_ParseError(ERR_NOTANAME, "Type %s cannot be redefined as an accessor", accessorname);
newt = &qcc_typeinfo[i];
break;
}
}
if (QCC_PR_CheckToken(":"))
{
@ -5210,18 +5260,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
forwarddeclaration = !QCC_PR_CheckToken("{");
}
/* Look to see if this type is already defined */
for(i=0;i<numtypeinfos;i++)
{
if (!qcc_typeinfo[i].typedefed)
continue;
if (STRCMP(qcc_typeinfo[i].name, classname) == 0)
{
newt = &qcc_typeinfo[i];
break;
}
}
newt = QCC_TypeForName(classname);
if (newt && newt->num_parms != 0)
redeclaration = true;
else
@ -5718,19 +5757,8 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
return newt;
}
type = NULL;
for (i = 0; i < numtypeinfos; i++)
{
if (!qcc_typeinfo[i].typedefed)
continue;
if (!STRCMP(qcc_typeinfo[i].name, name))
{
type = &qcc_typeinfo[i];
break;
}
}
if (i == numtypeinfos)
type = QCC_TypeForName(name);
if (!type)
{
if (!*name)
{
@ -5739,17 +5767,17 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
}
//some reacc types...
if (!stricmp("Void", name))
if (flag_acc && !stricmp("Void", name))
type = type_void;
else if (!stricmp("Real", name))
else if (flag_acc && !stricmp("Real", name))
type = type_float;
else if (!stricmp("Vector", name))
else if (flag_acc && !stricmp("Vector", name))
type = type_vector;
else if (!stricmp("Object", name))
else if (flag_acc && !stricmp("Object", name))
type = type_entity;
else if (!stricmp("String", name))
else if (flag_acc && !stricmp("String", name))
type = type_string;
else if (!stricmp("PFunc", name))
else if (flag_acc && !stricmp("PFunc", name))
type = type_function;
else
{

View file

@ -1698,6 +1698,11 @@ void GenericMenu(WPARAM wParam)
break;
case IDM_ABOUT:
#ifdef SVNVERSION
if (strcmp(SVNVERSION, "-"))
MessageBox(NULL, "FTE QuakeC Compiler "STRINGIFY(SVNVERSION)" ("__DATE__" "__TIME__")\nWritten by Forethought Entertainment, whoever that is.\n\nIf you have problems with wordpad corrupting your qc files, try saving them using utf-16 encoding via notepad.\nDecompiler component derived from frikdec.", "About", 0);
else
#endif
MessageBox(NULL, "FTE QuakeC Compiler ("__DATE__" "__TIME__")\nWritten by Forethought Entertainment, whoever that is.\n\nIf you have problems with wordpad corrupting your qc files, try saving them using utf-16 encoding via notepad.\nDecompiler component derived from frikdec.", "About", 0);
break;
@ -2853,7 +2858,7 @@ static LRESULT CALLBACK EditorWndProc(HWND hWnd,UINT message,
SendMessage(editor->editpane, SCI_CALLTIPCANCEL, 0, 0);
break;
}
//UpdateEditorTitle(editor);
UpdateEditorTitle(editor);
}
else
{
@ -3630,17 +3635,6 @@ static pbool EngineCommandWndf(HWND wnd, char *message, ...)
return EngineCommandWnd(wnd, finalmessage);
}
#ifdef _MSC_VER //ffs
#define strtoull _strtoui64
#ifndef PRIxPTR
#define PRIxPTR "Ix"
#endif
#else
#ifndef PRIxPTR
#define PRIxPTR "Ix"
#endif
#endif
DWORD WINAPI threadwrapper(void *args)
{
pbool hadstatus = false;
@ -5447,7 +5441,8 @@ void OptionsDialog(void)
int x;
int y;
int my;
int height;
int lheight;
int rheight;
int num;
int cflagsshown;
@ -5471,16 +5466,21 @@ void OptionsDialog(void)
wndclass.lpszClassName = OPTIONS_WINDOW_CLASS_NAME;
RegisterClass(&wndclass);
height = 0;
lheight = 0;
for (i = 0; optimisations[i].enabled; i++)
{
if (optimisations[i].flags & FLAG_HIDDENINGUI)
continue;
height++;
lheight++;
}
lheight = (lheight+1)/2; //double columns for optimisations
lheight *= 16;
lheight += 112;
lheight += 88;
cflagsshown = 0;
cflagsshown += 2; //hexenc, extended opcodes
for (i = 0; compiler_flag[i].enabled; i++)
{
if (compiler_flag[i].flags & FLAG_HIDDENINGUI)
@ -5489,27 +5489,28 @@ void OptionsDialog(void)
cflagsshown++;
}
height = (height+1)/2;
height *= 16;
height += 112;
while (cflagsshown*16 > height*flagcolums)
do
{
flagcolums++;
cflagsshown += flagcolums-1; //round up
rheight = (cflagsshown/flagcolums)*16;
if (height < (cflagsshown*16)/flagcolums)
height = (cflagsshown*16)/flagcolums;
rheight += 16+4+20; //extra parms cap,gap,parmsbox(min)
}while (rheight > lheight*flagcolums);
r.right = 408 + flagcolums*168;
if (r.right < 640)
r.right = 640;
height += 88;
r.left = GetSystemMetrics(SM_CXSCREEN)/2-320;
r.top = GetSystemMetrics(SM_CYSCREEN)/2-240;
r.bottom = r.top + height;
if (rheight > lheight)
r.bottom = r.top + rheight;
else
{
r.bottom = r.top + lheight;
rheight = lheight;
}
r.right += r.left;
@ -5525,7 +5526,7 @@ void OptionsDialog(void)
SendMessage(tipwnd, TTM_SETMAXTIPWIDTH, 0, 500);
subsection = CreateWindow("BUTTON", "Optimisations", WS_CHILD|WS_VISIBLE|BS_GROUPBOX,
0, 0, 400, height-40*4+24, optionsmenu, NULL, ghInstance, NULL);
0, 0, 400, lheight-40*4+24, optionsmenu, NULL, ghInstance, NULL);
num = 0;
for (i = 0; optimisations[i].enabled; i++)
@ -5563,7 +5564,7 @@ void OptionsDialog(void)
wnd = CreateWindow("BUTTON","O0",
WS_CHILD | WS_VISIBLE,
8,height-40*5+24,64,32,
8,lheight-40*5+24,64,32,
optionsmenu,
(HMENU)IDI_O_LEVEL0,
ghInstance,
@ -5571,7 +5572,7 @@ void OptionsDialog(void)
AddTip(tipwnd, wnd, "Disable optimisations completely, giving code more similar to vanilla.");
wnd = CreateWindow("BUTTON","O1",
WS_CHILD | WS_VISIBLE,
8+64,height-40*5+24,64,32,
8+64,lheight-40*5+24,64,32,
optionsmenu,
(HMENU)IDI_O_LEVEL1,
ghInstance,
@ -5579,7 +5580,7 @@ void OptionsDialog(void)
AddTip(tipwnd, wnd, "Enable simple optimisations (primarily size). Probably still breaks decompilers.");
wnd = CreateWindow("BUTTON","O2",
WS_CHILD | WS_VISIBLE,
8+64*2,height-40*5+24,64,32,
8+64*2,lheight-40*5+24,64,32,
optionsmenu,
(HMENU)IDI_O_LEVEL2,
ghInstance,
@ -5587,7 +5588,7 @@ void OptionsDialog(void)
AddTip(tipwnd, wnd, "Enable most optimisations. Does not optimise anything that is likely to break any engines.");
wnd = CreateWindow("BUTTON","O3",
WS_CHILD | WS_VISIBLE,
8+64*3,height-40*5+24,64,32,
8+64*3,lheight-40*5+24,64,32,
optionsmenu,
(HMENU)IDI_O_LEVEL3,
ghInstance,
@ -5595,7 +5596,7 @@ void OptionsDialog(void)
AddTip(tipwnd, wnd, "Enable unsafe optimisations. The extra optimisations may cause the progs to fail in certain cases, especially if used to compile addon modules.");
wnd = CreateWindow("BUTTON","Debug",
WS_CHILD | WS_VISIBLE,
8+64*4,height-40*5+24,64,32,
8+64*4,lheight-40*5+24,64,32,
optionsmenu,
(HMENU)IDI_O_DEBUG,
ghInstance,
@ -5603,7 +5604,7 @@ void OptionsDialog(void)
AddTip(tipwnd, wnd, "Disable any optimisations that might interfere with debugging somehow.");
wnd = CreateWindow("BUTTON","Default",
WS_CHILD | WS_VISIBLE,
8+64*5,height-40*5+24,64,32,
8+64*5,lheight-40*5+24,64,32,
optionsmenu,
(HMENU)IDI_O_DEFAULT,
ghInstance,
@ -5615,7 +5616,7 @@ void OptionsDialog(void)
"EDIT",
enginebinary,
WS_CHILD /*| ES_READONLY*/ | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL,
8, height-40-30*3, 400-16, 22,
8, lheight-40-30*3, 400-16, 22,
optionsmenu,
(HMENU)IDI_O_ENGINE,
ghInstance,
@ -5624,7 +5625,7 @@ void OptionsDialog(void)
"EDIT",
enginebasedir,
WS_CHILD /*| ES_READONLY*/ | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL,
8, height-40-30*2, 400-16, 22,
8, lheight-40-30*2, 400-16, 22,
optionsmenu,
(HMENU)IDI_O_ENGINEBASEDIR,
ghInstance,
@ -5633,7 +5634,7 @@ void OptionsDialog(void)
"EDIT",
enginecommandline,
WS_CHILD /*| ES_READONLY*/ | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL,
8, height-40-30, 400-16, 22,
8, lheight-40-30, 400-16, 22,
optionsmenu,
(HMENU)IDI_O_ENGINECOMMANDLINE,
ghInstance,
@ -5646,7 +5647,7 @@ void OptionsDialog(void)
wnd = CreateWindow("BUTTON","Apply",
WS_CHILD | WS_VISIBLE,
8,height-40,64,32,
8,lheight-40,64,32,
optionsmenu,
(HMENU)IDI_O_APPLY,
ghInstance,
@ -5654,7 +5655,7 @@ void OptionsDialog(void)
AddTip(tipwnd, wnd, "Use selected settings without saving them to disk.");
wnd = CreateWindow("BUTTON","Save",
WS_CHILD | WS_VISIBLE,
8+64,height-40,64,32,
8+64,lheight-40,64,32,
optionsmenu,
(HMENU)IDI_O_APPLYSAVE,
ghInstance,
@ -5662,7 +5663,7 @@ void OptionsDialog(void)
AddTip(tipwnd, wnd, "Use selected settings and save them to disk so that they're also used the next time you start fteqccgui.");
/*wnd = CreateWindow("BUTTON","progs.src",
WS_CHILD | WS_VISIBLE,
8+64*2,height-40,64,32,
8+64*2,lheight-40,64,32,
optionsmenu,
(HMENU)IDI_O_CHANGE_PROGS_SRC,
ghInstance,
@ -5723,7 +5724,7 @@ void OptionsDialog(void)
continue;
}
if (y > height-(88+40))
if (y > (cflagsshown/flagcolums)*16)
{
y = 4;
x += 168;
@ -5759,7 +5760,7 @@ void OptionsDialog(void)
extraparmsitem = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT",parameters,
WS_CHILD | WS_VISIBLE|ES_LEFT | ES_WANTRETURN |
ES_MULTILINE | ES_AUTOVSCROLL,
408,my,r.right-r.left - 408 - 8,height-my-4,
408,my,r.right-r.left - 408 - 8,rheight-my-4,
optionsmenu,
(HMENU)IDI_O_ADDITIONALPARAMETERS,
ghInstance,

View file

@ -114,6 +114,7 @@ extern int numCompilerConstants;
hashtable_t compconstantstable;
hashtable_t globalstable;
hashtable_t localstable;
hashtable_t typedeftable;
#ifdef WRITEASM
FILE *asmfile;
pbool asmfilebegun;
@ -214,6 +215,8 @@ struct {
{" F319", WARN_CONSTANTCOMPARISON},
{" F320", WARN_PARAMWITHNONAME},
{" F321", WARN_GMQCC_SPECIFIC},
{" F322", WARN_IFSTRING_USED},
{" F323", WARN_UNREACHABLECODE},
{" F208", WARN_NOTREFERENCEDCONST},
{" F209", WARN_EXTRAPRECACHE},
@ -232,6 +235,10 @@ struct {
//Q616: No function named
//Q617: Malloc failure
//Q618: Ran out of mem pointer space (malloc failure again)
//we can put longer alternative names here...
{" field-redeclared", WARN_DEPRECATEDWARNING},
{NULL}
};
@ -291,6 +298,9 @@ optimisations_t optimisations[] =
#define defaultkeyword FLAG_HIDDENINGUI|FLAG_ASDEFAULT|FLAG_MIDCOMPILE
#define nondefaultkeyword FLAG_HIDDENINGUI|0|FLAG_MIDCOMPILE
#define hideflag FLAG_HIDDENINGUI|FLAG_MIDCOMPILE
#define defaultflag FLAG_ASDEFAULT|FLAG_MIDCOMPILE
#define hidedefaultflag FLAG_HIDDENINGUI|FLAG_ASDEFAULT|FLAG_MIDCOMPILE
//global to store useage to, flags, codename, human-readable name, help text
compiler_flag_t compiler_flag[] = {
//keywords
@ -339,6 +349,8 @@ compiler_flag_t compiler_flag[] = {
{&keyword_accumulate, nondefaultkeyword,"accumulate", "Keyword: accumulate", "Disables the 'accumulate' keyword."},
//options
{&flag_acc, 0, "acc", "Reacc support", "Reacc is a pascall like compiler. It was released before the Quake source was released. This flag has a few effects. It sorts all qc files in the current directory into alphabetical order to compile them. It also allows Reacc global/field distinctions, as well as allows ¦ as EOF. Whilst case insensitivity and lax type checking are supported by reacc, they are seperate compiler flags in fteqcc."}, //reacc like behaviour of src files.
{&flag_qccx, FLAG_MIDCOMPILE,"qccx", "QCCX syntax", "WARNING: This syntax makes mods inherantly engine specific.\nDo NOT use unless you know what you're doing.This is provided for compatibility only\nAny entity hacks will be unsupported in FTEQW, DP, and others, resulting in engine crashes if the code in question is executed."},
{&keywords_coexist, FLAG_ASDEFAULT, "kce", "Keywords Coexist", "If you want keywords to NOT be disabled when they a variable by the same name is defined, check here."},
{&output_parms, 0, "parms", "Define offset parms", "if PARM0 PARM1 etc should be defined by the compiler. These are useful if you make use of the asm keyword for function calls, or you wish to create your own variable arguments. This is an easy way to break decompilers."}, //controls weather to define PARMx for the parms (note - this can screw over some decompilers)
{&autoprototype, 0, "autoproto", "Automatic Prototyping","Causes compilation to take two passes instead of one. The first pass, only the definitions are read. The second pass actually compiles your code. This means you never have to remember to prototype functions again."}, //so you no longer need to prototype functions and things in advance.
@ -346,12 +358,11 @@ compiler_flag_t compiler_flag[] = {
{&flag_guiannotate, FLAG_MIDCOMPILE,"annotate", "Annotate Sourcecode", "Annotate source code with assembler statements on compile (requires gui)."},
{&flag_nullemptystr, FLAG_MIDCOMPILE,"nullemptystr", "Null String Immediates", "Empty string immediates will have the raw value 0 instead of 1."},
{&flag_ifstring, FLAG_MIDCOMPILE,"ifstring", "if(string) fix", "Causes if(string) to behave identically to if(string!="") This is most useful with addons of course, but also has adverse effects with FRIK_FILE's fgets, where it becomes impossible to determin the end of the file. In such a case, you can still use asm {IF string 2;RETURN} to detect eof and leave the function."}, //correction for if(string) no-ifstring to get the standard behaviour.
{&flag_iffloat, FLAG_MIDCOMPILE,"iffloat","if(-0.0) fix","Fixes certain floating point logic."},
{&flag_ifvector, FLAG_MIDCOMPILE|FLAG_ASDEFAULT,"ifvector","if('0 1 0') fix","Fixes conditional vector logic."},
{&flag_vectorlogic, FLAG_MIDCOMPILE|FLAG_ASDEFAULT,"vectorlogic","v&&v||v fix", "Fixes conditional vector logic."},
{&flag_iffloat, FLAG_MIDCOMPILE,"iffloat", "if(-0.0) fix","Fixes certain floating point logic."},
{&flag_ifvector, defaultflag, "ifvector", "if('0 1 0') fix","Fixes conditional vector logic."},
{&flag_vectorlogic, defaultflag, "vectorlogic", "v&&v||v fix", "Fixes conditional vector logic."},
{&flag_brokenarrays, FLAG_MIDCOMPILE,"brokenarray", "array[0] omission", "Treat references to arrays as references to the first index of said array, to replicate an old fteqcc bug."},
{&flag_rootconstructor, FLAG_MIDCOMPILE,"rootconstructor","root constructor first", "When enabled, the root constructor should be called first like in c++."},
{&flag_acc, 0, "acc", "Reacc support", "Reacc is a pascall like compiler. It was released before the Quake source was released. This flag has a few effects. It sorts all qc files in the current directory into alphabetical order to compile them. It also allows Reacc global/field distinctions, as well as allows ¦ as EOF. Whilst case insensitivity and lax type checking are supported by reacc, they are seperate compiler flags in fteqcc."}, //reacc like behaviour of src files.
{&flag_caseinsensitive, 0, "caseinsens", "Case insensitivity", "Causes fteqcc to become case insensitive whilst compiling names. It's generally not advised to use this as it compiles a little more slowly and provides little benefit. However, it is required for full reacc support."}, //symbols will be matched to an insensitive case if the specified case doesn't exist. This should b usable for any mod
{&flag_laxcasts, FLAG_MIDCOMPILE,"lax", "Lax type checks", "Disables many errors (generating warnings instead) when function calls or operations refer to two normally incompatible types. This is required for reacc support, and can also allow certain (evil) mods to compile that were originally written for frikqcc."}, //Allow lax casting. This'll produce loadsa warnings of course. But allows compilation of certain dodgy code.
{&flag_hashonly, FLAG_MIDCOMPILE,"hashonly", "Hash-only constants", "Allows use of only #constant for precompiler constants, allows certain preqcc using mods to compile"},
@ -365,12 +376,16 @@ compiler_flag_t compiler_flag[] = {
{&verbose, FLAG_MIDCOMPILE,"verbose", "Verbose", "Lots of extra compiler messages."},
{&flag_typeexplicit, FLAG_MIDCOMPILE,"typeexplicit", "Explicit types", "All type conversions must be explicit or directly supported by instruction set."},
{&flag_noboundchecks, FLAG_MIDCOMPILE,"noboundchecks","Disable Bound Checks", "Disable array index checks, speeding up array access but can result in your code misbehaving."},
{&flag_qccx, FLAG_MIDCOMPILE,"qccx", "QCCX syntax", "WARNING: This syntax makes mods inherantly engine specific.\nDo NOT use unless you know what you're doing.This is provided for compatibility only\nAny entity hacks will be unsupported in FTEQW, DP, and others, resulting in engine crashes if the code in question is executed."},
{&flag_attributes, FLAG_MIDCOMPILE|FLAG_HIDDENINGUI,"attributes", "[[attributes]]", "WARNING: This syntax conflicts with vector constructors."},
{&flag_assumevar, FLAG_MIDCOMPILE|FLAG_HIDDENINGUI,"assumevar", "explicit consts", "Initialised globals will be considered non-const by default."},
{&flag_dblstarexp, FLAG_MIDCOMPILE|FLAG_HIDDENINGUI,"ssp","** exponent", "Treat ** as an operator for exponents, instead of multiplying by a dereferenced pointer."},
{&flag_attributes, hideflag, "attributes", "[[attributes]]", "WARNING: This syntax conflicts with vector constructors."},
{&flag_assumevar, hideflag, "assumevar", "explicit consts", "Initialised globals will be considered non-const by default."},
{&flag_dblstarexp, hideflag, "ssp", "** exponent", "Treat ** as an operator for exponents, instead of multiplying by a dereferenced pointer."},
{&flag_cpriority, hideflag, "cpriority", "C Operator Priority", "QC treats !a&&b as equivelent to !(a&&b). When this is set, behaviour will be (!a)&&b as in C. Other operators are also affected in similar ways."},
{&flag_allowuninit, hideflag, "allowuninit", "Uninitialised Locals", "Permit optimisations that may result in locals being uninitialised. This may allow for greater reductions in temps."},
{&flag_nopragmafileline,FLAG_MIDCOMPILE,"nofileline", "Ignore #pragma file", "Ignores #pragma file(foo) and #pragma line(foo), so that errors and symbols reflect the actual lines, instead of the original source."},
// {&flag_lno, hidedefaultflag,"lno", "Gen Debugging Info", "Writes debugging info."},
// {&flag_utf8, hidedefaultflag,"utf8", "Unicode", "Assume files to be UTF-8 encoded, instead of iso8859-1."},
{&flag_embedsrc, FLAG_MIDCOMPILE,"embedsrc", "Embed Sources", "Write the sourcecode into the output file."},
{&flag_embedsrc, FLAG_MIDCOMPILE,"embedsrc", "Embed Sources", "Write the sourcecode into the output file. The resulting .dat can be opened as a standard zip archive (or by fteqccgui).\nGood for GPL compliance!"},
// {&flag_noreflection, FLAG_MIDCOMPILE,"omitinternals","Omit Reflection Info", "Keeps internal symbols private (equivelent to unix's hidden visibility). This has the effect of reducing filesize, thwarting debuggers, and breaking saved games. This allows you to use arrays without massively bloating the size of your progs.\nWARNING: The bit about breaking saved games was NOT a joke, but does not apply to menuqc or csqc. It also interferes with FTE_MULTIPROGS."},
{NULL}
};
@ -1628,6 +1643,12 @@ pbool QCC_WriteData (int crc)
for (dupewarncount = 0, def = pr.def_head.next ; def ; def = def->next)
{
if (def->scope && !def->isstatic && !def->scope->privatelocals)
{ //if we're merging locals, then we shouldn't ever bother writing those globals. it just confuses debuggers etc. they're utterly pointless.
//which may be a problem if they're things that the engine is going to be swapping around... which they shouldn't be.
continue;
}
/* if (def->type->type == ev_vector || (def->type->type == ev_field && def->type->aux_type->type == ev_vector))
{ //do the references, so we don't get loadsa not referenced VEC_HULL_MINS_x
s_file = def->s_file;
@ -1801,7 +1822,7 @@ pbool QCC_WriteData (int crc)
if (def->shared)
dd->type |= DEF_SHARED;
if (opt_locals && (def->scope || !strcmp(def->name, "IMMEDIATE")))
if (opt_locals && ((def->scope&&!def->isstatic) || !strcmp(def->name, "IMMEDIATE")))
{
dd->s_name = 0;
optres_locals += strlen(def->name);
@ -3035,6 +3056,8 @@ QCC_type_t *QCC_PR_NewType (char *name, int basictype, pbool typedefed)
qcc_typeinfo[numtypeinfos].size = type_size[basictype];
qcc_typeinfo[numtypeinfos].typedefed = typedefed;
if (typedefed)
pHash_Add(&typedeftable, name, &qcc_typeinfo[numtypeinfos], qccHunkAlloc(sizeof(bucket_t)));
numtypeinfos++;
@ -3123,6 +3146,8 @@ void QCC_PR_BeginCompilation (void *memory, int memsize)
pr_error_count = 0;
pr_warning_count = 0;
recursivefunctiontype = 0;
QCC_PrioritiseOpcodes();
}
/*
@ -4031,33 +4056,33 @@ void QCC_PR_CommandLinePrecompilerOptions (void)
if (myargv[i][2] >= '0' && myargv[i][2] <= '3')
{
}
else if (!strnicmp(myargv[i]+2, "no-", 3))
{
if (myargv[i][5])
{
for (p = 0; optimisations[p].enabled; p++)
{
if ((*optimisations[p].abbrev && !stricmp(myargv[i]+5, optimisations[p].abbrev)) || !stricmp(myargv[i]+5, optimisations[p].fullname))
{
*optimisations[p].enabled = false;
break;
}
}
}
}
else
{
if (myargv[i][2])
for (p = 0; optimisations[p].enabled; p++)
if ((*optimisations[p].abbrev && !stricmp(myargv[i]+2, optimisations[p].abbrev)) || !stricmp(myargv[i]+2, optimisations[p].fullname))
char *a = myargv[i]+2;
pbool state = true;
if (!strnicmp(a, "no-", 3))
{
*optimisations[p].enabled = true;
a+=3;
state = false;
}
for (p = 0; optimisations[p].enabled; p++)
{
if ((*optimisations[p].abbrev && !stricmp(a, optimisations[p].abbrev)) || !stricmp(a, optimisations[p].fullname))
{
*optimisations[p].enabled = state;
break;
}
}
if (!optimisations[p].enabled)
{
if (!stricmp(a, "overlap-locals"))
opt_locals_overlapping = state;
else
QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised optimisation parameter (%s)", myargv[i]);
}
}
}
else if ( !strnicmp(myargv[i], "-K", 2) || WINDOWSARG(!strnicmp(myargv[i], "/K", 2)) )
{
@ -4125,7 +4150,8 @@ void QCC_PR_CommandLinePrecompilerOptions (void)
else if (!strcmp(myargv[i]+5, "gmqcc"))
{
flag_ifvector = flag_vectorlogic = true;
flag_dblstarexp = flag_attributes = flag_assumevar = pr_subscopedlocals = true;
flag_dblstarexp = flag_attributes = flag_assumevar = pr_subscopedlocals = flag_cpriority = flag_allowuninit = true;
opt_logicops = true;
qccwarningaction[WARN_CONSTANTCOMPARISON] = WA_IGNORE;
qccwarningaction[WARN_POINTLESSSTATEMENT] = WA_IGNORE;
qccwarningaction[WARN_OVERFLOW] = WA_IGNORE;
@ -4140,7 +4166,7 @@ void QCC_PR_CommandLinePrecompilerOptions (void)
keyword_int = keyword_integer = keyword_struct = keyword_union = keyword_enum = keyword_enumflags = false;
keyword_thinktime = keyword_until = keyword_loop = false;
keyword_wrap = keyword_weak = true; //wrong, but needed because we don't accept useless function bodies without weak
keyword_wrap = keyword_weak = false;
keyword_enum = true;
keyword_break = keyword_continue = keyword_for = keyword_goto = true;
@ -4185,6 +4211,16 @@ void QCC_PR_CommandLinePrecompilerOptions (void)
flag_ifstring = state;
else if (!stricmp(arg, "true-empty-strings"))
flag_brokenifstring = state;
else if (!stricmp(arg, "lno"))
; //currently we always try to write lno files...
else if (!stricmp(arg, "utf8"))
; //we always interpret input as utf-8, and thus output strings are 'utf-8' too. -fno-utf8 might be useful to asciify inputs, but that'll just break quake-encoded text, so why bother
else if (!stricmp(arg, "return-assignments"))
; //should really be a warning instead
else if (!stricmp(arg, "relaxed-switch"))
; //again should be a warning/werror
else if (!stricmp(arg, "bail-on-werror"))
;
else
QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised flag parameter (%s)", myargv[i]);
}
@ -4212,7 +4248,8 @@ void QCC_PR_CommandLinePrecompilerOptions (void)
else if ( !strnicmp(myargv[i], "-W", 2) || WINDOWSARG(!strnicmp(myargv[i], "/W", 2)) )
{
if (!stricmp(myargv[i]+2, "all"))
char *a = myargv[i]+2;
if (!stricmp(a, "all"))
{
for (j = 0; j < ERR_PARSEERRORS; j++)
if (qccwarningaction[j] == WA_IGNORE)
@ -4223,22 +4260,22 @@ void QCC_PR_CommandLinePrecompilerOptions (void)
qccwarningaction[j] = WA_WARN;
}
}
else if (!stricmp(myargv[i]+2, "extra"))
else if (!stricmp(a, "extra"))
{
for (j = 0; j < ERR_PARSEERRORS; j++)
if (qccwarningaction[j] == WA_IGNORE)
qccwarningaction[j] = WA_WARN;
}
else if (!stricmp(myargv[i]+2, "none"))
else if (!stricmp(a, "none"))
{
for (j = 0; j < ERR_PARSEERRORS; j++)
qccwarningaction[j] = WA_IGNORE;
}
else if(!stricmp(myargv[i]+2, "error"))
else if(!stricmp(a, "error"))
{
werror = true;
}
else if (!stricmp(myargv[i]+2, "no-mundane"))
else if (!stricmp(a, "no-mundane"))
{ //disable mundane performance/efficiency/blah warnings that don't affect code.
qccwarningaction[WARN_SAMENAMEASGLOBAL] = WA_IGNORE;
qccwarningaction[WARN_DUPLICATEDEFINITION] = WA_IGNORE;
@ -4259,25 +4296,21 @@ void QCC_PR_CommandLinePrecompilerOptions (void)
}
else
{
unsigned char action = WA_WARN;
p = -1;
if (!strnicmp(myargv[i]+2, "error-", 6))
if (!strnicmp(a, "error-", 6))
{
p = QCC_WarningForName(myargv[i]+8);
if (p >= 0)
qccwarningaction[p] = WA_ERROR;
a+= 6;
action = WA_ERROR;
}
else if (!strnicmp(myargv[i]+2, "no-", 3))
else if (!strnicmp(a, "no-", 3))
{
p = QCC_WarningForName(myargv[i]+5);
if (p >= 0)
qccwarningaction[p] = WA_IGNORE;
a+=3;
action = WA_IGNORE;
}
else
{
p = QCC_WarningForName(myargv[i]+2);
p = QCC_WarningForName(a);
if (p >= 0)
qccwarningaction[p] = WA_WARN;
}
qccwarningaction[p] = action;
if (p < 0)
QCC_PR_Warning(0, NULL, WARN_BADPARAMS, "Unrecognised warning parameter (%s)", myargv[i]);
@ -4613,13 +4646,13 @@ pbool QCC_main (int argc, char **argv) //as part of the quake engine
pHash_RemoveData = &Hash_RemoveData;
MAX_REGS = 1<<17;
MAX_STRINGS = 1000000;
MAX_STRINGS = 1<<21;
MAX_GLOBALS = 1<<17;
MAX_FIELDS = 1<<12;
MAX_STATEMENTS = 0x80000;
MAX_FUNCTIONS = 32768;
maxtypeinfos = 32768;
MAX_CONSTANTS = 4096;
MAX_FIELDS = 1<<13;
MAX_STATEMENTS = 0x100000;
MAX_FUNCTIONS = 1<<15;
maxtypeinfos = 1<<16;
MAX_CONSTANTS = 1<<12;
strcpy(destfile, "");
compressoutput = 0;
@ -4741,6 +4774,7 @@ pbool QCC_main (int argc, char **argv) //as part of the quake engine
qcc_pr_globals = (void *)qccHunkAlloc(sizeof(float) * (MAX_REGS + MAX_LOCALS + MAX_TEMPS));
numpr_globals=0;
Hash_InitTable(&typedeftable, 1024, qccHunkAlloc(Hash_BytesForBuckets(1024)));
Hash_InitTable(&globalstable, MAX_REGS/2, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS/2)));
Hash_InitTable(&localstable, 128, qccHunkAlloc(Hash_BytesForBuckets(128)));
Hash_InitTable(&floatconstdefstable, MAX_REGS/2+1, qccHunkAlloc(Hash_BytesForBuckets(MAX_REGS/2+1)));
@ -4924,6 +4958,8 @@ memset(pr_immediate_string, 0, sizeof(pr_immediate_string));
{
void StartNewStyleCompile(void);
newstyle:
if (flag_filetimes)
QCC_PR_Warning(0, qccmsrc, 0, "-ffiletimes unsupported with this input");
newstylesource = true;
originalqccmsrc = qccmsrc;
pr_source_line = qccmline = 1;

View file

@ -9144,14 +9144,14 @@ static void QCBUILTIN PF_setcolors (pubprogfuncs_t *prinst, struct globalvars_s
client = &svs.clients[entnum-1];
client->edict->v->team = (i & 15) + 1;
sprintf(number, "%i", i>>4);
Q_snprintfz(number, sizeof(number), "%i", i>>4);
if (strcmp(number, Info_ValueForKey(client->userinfo, "topcolor")))
{
Info_SetValueForKey(client->userinfo, "topcolor", number, sizeof(client->userinfo));
key = "topcolor";
}
sprintf(number, "%i", i&15);
Q_snprintfz(number, sizeof(number), "%i", i&15);
if (strcmp(number, Info_ValueForKey(client->userinfo, "bottomcolor")))
{
Info_SetValueForKey(client->userinfo, "bottomcolor", number, sizeof(client->userinfo));

View file

@ -313,6 +313,7 @@ void VARGS SV_Error (char *error, ...)
va_list argptr;
static char string[1024];
static qboolean inerror = false;
int i;
if (inerror)
{
@ -346,6 +347,13 @@ void VARGS SV_Error (char *error, ...)
if (sv.state)
SV_FinalMessage (va("server crashed: %s\n", string));
//flag all players as unspawned, so gamecode doesn't recurse while already crashing. that sort of thing just results in more crashes.
for (i = 0; i < sv.allocated_client_slots; i++)
svs.clients[i].spawned = false;
sv.spawned_client_slots = 0;
sv.spawned_observer_slots = 0;
SV_UnspawnServer();
#ifndef SERVERONLY
if (cls.state)

View file

@ -2053,7 +2053,7 @@ typedef struct {
} qcstat_t;
qcstat_t qcstats[MAX_CL_STATS];
int numqcstats;
void SV_QCStatEval(int type, const char *name, evalc_t *field, eval_t *global, int statnum)
static void SV_QCStatEval(int type, const char *name, evalc_t *field, eval_t *global, int statnum)
{
int i;
if (numqcstats == sizeof(qcstats)/sizeof(qcstats[0]))
@ -2081,10 +2081,13 @@ void SV_QCStatEval(int type, const char *name, evalc_t *field, eval_t *global, i
qcstats[i].type = type;
qcstats[i].statnum = statnum;
Q_strncpyz(qcstats[i].name, name, sizeof(qcstats[i].name));
if (type < 0)
memset(&qcstats[i].eval, 0, sizeof(qcstats[i].eval));
if (type <= 0)
qcstats[i].eval.g = global;
else
else if (field)
memcpy(&qcstats[i].eval.c, field, sizeof(evalc_t));
else
qcstats[i].type = ev_void;
}
void SV_QCStatGlobal(int type, const char *globalname, int statnum)
@ -2154,7 +2157,7 @@ void SV_UpdateQCStats(edict_t *ent, int *statsi, char const** statss, float *sta
{
eval_t *eval;
t = qcstats[i].type;
if (t < 0)
if (t <= 0)
{
t = -t;
eval = qcstats[i].eval.g;

View file

@ -1,6 +1,8 @@
!!permu BUMP
!!permu SKELETAL
!!permu FRAMEBLEND
!!cvarf r_glsl_offsetmapping_scale
!!samps normalmap specular
//light pre-pass rendering (defered lighting)
//this is the initial pass, that draws the surface normals and depth to the initial colour buffer
@ -11,8 +13,11 @@
varying vec3 eyevector;
#endif
varying vec3 norm, tang, bitang;
varying vec3 norm;
#if defined(BUMP)
varying vec3 tang, bitang;
#endif
#if defined(BUMP) || defined(SPECULAR)
varying vec2 tc;
#endif
#ifdef VERTEX_SHADER
@ -22,10 +27,12 @@ void main()
{
#if defined(BUMP)
gl_Position = skeletaltransform_nst(norm, tang, bitang);
tc = v_texcoord;
#else
gl_Position = skeletaltransform_n(norm);
#endif
#if defined(BUMP) || defined(SPECULAR)
tc = v_texcoord;
#endif
#if defined(OFFSETMAPPING)
vec3 eyeminusvertex = e_eyepos - v_position.xyz;
@ -48,12 +55,23 @@ void main()
#endif
vec3 onorm;
vec4 ospec;
//need to write surface normals so that light shines on the surfaces properly
#if defined(BUMP)
vec3 bm = 2.0*texture2D(s_normalmap, tc).xyz - 1.0;
onorm = normalize(bm.x * tang + bm.y * bitang + bm.z * norm);
#else
onorm = norm;
#endif
gl_FragColor = vec4(onorm.xyz, gl_FragCoord.z);
//we need to write specular exponents if we want per-pixel control over that
//#if defined(SPECULAR)
ospec = texture2D(s_specular, tc);
//#else
// ospec = vec4(0.0, 0.0, 0.0, 0.0);
//#endif
gl_FragColor = vec4(onorm.xyz, ospec.a * FTE_SPECULAR_EXPONENT);
}
#endif

View file

@ -1,9 +1,17 @@
//this shader is a light shader. ideally drawn with a quad covering the entire region
//the output is contribution from this light (which will be additively blended)
//you can blame Electro for much of the maths in here.
//fixme: no fog
!!ver 100 450
//FIXME: !!permu FOG
!!samps shadowmap 2
//s_t0 is the normals and depth
#define USE_ARB_SHADOW
#include "sys/defs.h"
#include "sys/pcf.h"
//s_t0 is the depth
//s_t1 is the normals+spec-exponent
//output should be amount of light hitting the surface.
varying vec4 tf;
@ -15,136 +23,9 @@ void main()
}
#endif
#ifdef FRAGMENT_SHADER
uniform sampler2D s_t0; //norm.xyz, depth
uniform vec3 l_lightposition;
uniform mat4 m_invviewprojection;
uniform vec3 l_lightcolour;
uniform float l_lightradius;
uniform mat4 l_cubematrix;
#ifdef PCF
#define USE_ARB_SHADOW
#ifndef USE_ARB_SHADOW
//fall back on regular samplers if we must
#define sampler2DShadow sampler2D
#endif
uniform sampler2DShadow s_shadowmap;
//FIXME: shadowmaps need to be atlased!
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(vec4 cubeproj)
{
#ifdef SPOT
//bias it. don't bother figuring out which side or anything, its not needed
//l_projmatrix contains the light's projection matrix so no other magic needed
return ((cubeproj.xyz-vec3(0.0,0.0,0.015))/cubeproj.w + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5);
//#elif defined(CUBESHADOW)
// vec3 shadowcoord = vshadowcoord.xyz / vshadowcoord.w;
// #define dosamp(x,y) shadowCube(s_shadowmap, shadowcoord + vec2(x,y)*texscale.xy).r
#else
//figure out which axis to use
//texture is arranged thusly:
//forward left up
//back right down
vec3 dir = abs(cubeproj.xyz);
//assume z is the major axis (ie: forward from the light)
vec3 t = cubeproj.xyz;
float ma = dir.z;
vec3 axis = vec3(0.5/3.0, 0.5/2.0, 0.5);
if (dir.x > ma)
{
ma = dir.x;
t = cubeproj.zyx;
axis.x = 0.5;
}
if (dir.y > ma)
{
ma = dir.y;
t = cubeproj.xzy;
axis.x = 2.5/3.0;
}
//if the axis is negative, flip it.
if (t.z > 0.0)
{
axis.y = 1.5/2.0;
t.z = -t.z;
}
//we also need to pass the result through the light's projection matrix too
//the 'matrix' we need only contains 5 actual values. and one of them is a -1. So we might as well just use a vec4.
//note: the projection matrix also includes scalers to pinch the image inwards to avoid sampling over borders, as well as to cope with non-square source image
//the resulting z is prescaled to result in a value between -0.5 and 0.5.
//also make sure we're in the right quadrant type thing
return axis + ((l_shadowmapproj.xyz*t.xyz + vec3(0.0, 0.0, l_shadowmapproj.w)) / -t.z);
#endif
}
float ShadowmapFilter(vec4 vtexprojcoord)
{
vec3 shadowcoord = ShadowmapCoord(vtexprojcoord);
#if 0//def GL_ARB_texture_gather
vec2 ipart, fpart;
#define dosamp(x,y) textureGatherOffset(s_shadowmap, ipart.xy, vec2(x,y)))
vec4 tl = step(shadowcoord.z, dosamp(-1.0, -1.0));
vec4 bl = step(shadowcoord.z, dosamp(-1.0, 1.0));
vec4 tr = step(shadowcoord.z, dosamp(1.0, -1.0));
vec4 br = step(shadowcoord.z, dosamp(1.0, 1.0));
//we now have 4*4 results, woo
//we can just average them for 1/16th precision, but that's still limited graduations
//the middle four pixels are 'full strength', but we interpolate the sides to effectively give 3*3
vec4 col = vec4(tl.ba, tr.ba) + vec4(bl.rg, br.rg) + //middle two rows are full strength
mix(vec4(tl.rg, tr.rg), vec4(bl.ba, br.ba), fpart.y); //top+bottom rows
return dot(mix(col.rgb, col.agb, fpart.x), vec3(1.0/9.0)); //blend r+a, gb are mixed because its pretty much free and gives a nicer dot instruction instead of lots of adds.
#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
#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)
#endif
float s = 0.0;
#if r_glsl_pcf >= 1 && r_glsl_pcf < 5
s += dosamp(0.0, 0.0);
return s;
#elif r_glsl_pcf >= 5 && r_glsl_pcf < 9
s += dosamp(-1.0, 0.0);
s += dosamp(0.0, -1.0);
s += dosamp(0.0, 0.0);
s += dosamp(0.0, 1.0);
s += dosamp(1.0, 0.0);
return s/5.0;
#else
s += dosamp(-1.0, -1.0);
s += dosamp(-1.0, 0.0);
s += dosamp(-1.0, 1.0);
s += dosamp(0.0, -1.0);
s += dosamp(0.0, 0.0);
s += dosamp(0.0, 1.0);
s += dosamp(1.0, -1.0);
s += dosamp(1.0, 0.0);
s += dosamp(1.0, 1.0);
return s/9.0;
#endif
#endif
}
#else
float ShadowmapFilter(vec4 vtexprojcoord)
{
return 1.0;
}
#endif
#define out_diff fte_fragdata0
#define out_spec fte_fragdata1
vec3 calcLightWorldPos(vec2 screenPos, float depth)
{
@ -154,16 +35,13 @@ vec3 calcLightWorldPos(vec2 screenPos, float depth)
void main ()
{
vec3 lightColour = l_lightcolour.rgb;
float lightIntensity = 1.0;
float lightAttenuation = l_lightradius; // fixme: just use the light radius for now, use better near/far att math separately once working
float radiusFar = l_lightradius;
float radiusNear = l_lightradius*0.5;
vec2 fc;
fc = tf.xy / tf.w;
vec4 data = texture2D(s_t0, (1.0 + fc) / 2.0);
float depth = data.a;
vec2 fc = tf.xy / tf.w;
vec2 gc = (1.0 + fc) / 2.0;
float depth = texture2D(s_t0, gc).r;
vec4 data = texture2D(s_t1, gc);
vec3 norm = data.xyz;
float spec_exponent = data.a;
/* calc where the wall that generated this sample came from */
vec3 worldPos = calcLightWorldPos(fc, depth);
@ -171,22 +49,26 @@ void main ()
/*we need to know the cube projection (for both cubemaps+shadows)*/
vec4 cubeaxis = l_cubematrix*vec4(worldPos.xyz, 1.0);
/*calc diffuse lighting term*/
/*calc ambient lighting term*/
vec3 lightDir = l_lightposition - worldPos;
float zdiff = 1.0 - clamp(length(lightDir) / lightAttenuation, 0.0, 1.0);
float atten = (radiusFar * zdiff) / (radiusFar - radiusNear);
atten = pow(atten, 2.0);
float atten = max(1.0 - (dot(lightDir, lightDir)/(l_lightradius*l_lightradius)), 0.0);
/*calc diffuse lighting term*/
lightDir = normalize(lightDir);
float nDotL = dot(norm, lightDir);
float lightDiffuse = max(0.0, nDotL) * atten;
float lightDiffuse = max(0.0, nDotL);
/*calc specular term*/
//fixme
/*calc specular lighting term*/
vec3 halfdir = normalize(normalize(e_eyepos - worldPos) + lightDir); //ASSUMPTION: e_eyepos requires an identity modelmatrix (true for world+sprites, but usually not for models/bsps)
float spec = pow(max(dot(halfdir, norm), 0.0), spec_exponent);
//fixme: apply fog
//fixme: output a specular term
//fixme: apply fog?
//fixme: cubemap filters
gl_FragColor = vec4(lightDiffuse * (lightColour * lightIntensity) * ShadowmapFilter(cubeaxis), 1.0);
float shadows = ShadowmapFilter(s_shadowmap, cubeaxis);
lightColour *= atten;
out_diff = vec4(lightColour * (l_lightcolourscale.x + l_lightcolourscale.y*lightDiffuse*shadows), 1.0);
out_spec = vec4(lightColour * l_lightcolourscale.z*spec*shadows, 1.0);
}
#endif

View file

@ -1,5 +1,6 @@
!!permu BUMP //for offsetmapping rather than bumpmapping (real bumps are handled elsewhere)
!!cvarf r_glsl_offsetmapping_scale
!!samps 2
//the final defered lighting pass.
//the lighting values were written to some render target, which is fed into this shader, and now we draw all the wall textures with it.
@ -29,7 +30,6 @@ void main ()
}
#endif
#ifdef FRAGMENT_SHADER
uniform sampler2D s_t0; //light gbuffer
#ifdef OFFSETMAPPING
#include "sys/offsetmapping.h"
#endif
@ -44,16 +44,19 @@ void main ()
vec2 nst;
nst = tf.xy / tf.w;
nst = (1.0 + nst) / 2.0;
vec4 l = texture2D(s_t0, nst);
vec4 dl = texture2D(s_t0, nst); //diffuse lighting
vec4 sl = texture2D(s_t1, nst); //specular lighting
vec4 c = texture2D(s_diffuse, tc);
vec4 s = texture2D(s_specular, tc);
vec4 f = texture2D(s_fullbright, tc);
//fixme: top+bottom should add upper+lower colours to c here
vec3 lmsamp = texture2D(s_lightmap, lm).rgb*e_lmscale.rgb;
//fixme: fog the legacy lightmap data
vec3 diff = l.rgb;
// vec3 chrom = diff / (0.001 + dot(diff, vec3(0.3, 0.59, 0.11)));
// vec3 spec = chrom * l.a;
vec3 diff = dl.rgb + lmsamp;
vec3 spec = sl.rgb * float(SPECMUL); //should be rgb, but whatever.
//fixme: do specular somehow
gl_FragColor = vec4((diff + lmsamp) * c.xyz, 1.0);
gl_FragColor = vec4(diff*c.rgb + spec*s.rgb + f.rgb, 1.0);
//fixme: fullbrights should add to the rgb value
}
#endif

View file

@ -225,7 +225,7 @@ void main ()
float colorscale = max(1.0 - (dot(lightvector, lightvector)/(l_lightradius*l_lightradius)), 0.0);
#ifdef PCF
/*filter the light by the shadowmap. logically a boolean, but we allow fractions for softer shadows*/
colorscale *= ShadowmapFilter(s_shadowmap);
colorscale *= ShadowmapFilter(s_shadowmap, vtexprojcoord);
#endif
#if defined(SPOT)
/*filter the colour by the spotlight. discard anything behind the light so we don't get a mirror image*/

View file

@ -3715,7 +3715,7 @@ static qboolean JCL_ServerFeatureReply(jclient_t *jcl, xmltree_t *tree, struct i
return true;
}
static qboolean JCL_ServerPeerReply(jclient_t *jcl, xmltree_t *tree, struct iq_s *iq)
/*static qboolean JCL_ServerPeerReply(jclient_t *jcl, xmltree_t *tree, struct iq_s *iq)
{
xmltree_t *query = XML_ChildOfTreeNS(tree, "http://jabber.org/protocol/disco#info", "query", 0);
xmltree_t *feature;
@ -3751,7 +3751,7 @@ static qboolean JCL_ServerPeerReply(jclient_t *jcl, xmltree_t *tree, struct iq_s
return true;
}
/*static qboolean JCL_ServerItemsReply(jclient_t *jcl, xmltree_t *tree, struct iq_s *iq)
static qboolean JCL_ServerItemsReply(jclient_t *jcl, xmltree_t *tree, struct iq_s *iq)
{
xmltree_t *query = XML_ChildOfTreeNS(tree, "http://jabber.org/protocol/disco#items", "query", 0);
xmltree_t *item;