diff --git a/engine/Makefile b/engine/Makefile index 5f19bcad..9abb2b08 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -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) diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 91643faf..22d8d7d3 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -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) { diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 0534275b..f70fa2a1 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -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 diff --git a/engine/client/client.h b/engine/client/client.h index d1414702..ffd94e84 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -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 diff --git a/engine/client/image.c b/engine/client/image.c index 66b4dc0a..0c1c0c94 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -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; diff --git a/engine/client/in_generic.c b/engine/client/in_generic.c index 0e68d5fb..c8307023 100644 --- a/engine/client/in_generic.c +++ b/engine/client/in_generic.c @@ -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++; diff --git a/engine/client/keys.c b/engine/client/keys.c index ddde43b0..f6ae286b 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -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) { diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index bebf05c3..f46cc77d 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -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; } diff --git a/engine/client/m_options.c b/engine/client/m_options.c index ab82ccbc..63f80198 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -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*/ diff --git a/engine/client/net_master.c b/engine/client/net_master.c index 060b3fa5..448f039f 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -1437,7 +1437,10 @@ void CLMaster_AddMaster_Worker_Resolve(void *ctx, void *data, size_t a, size_t b } //add the main ip address - work->adr = adrs[0]; + 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) diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 73635fe3..2fac5e05 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -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]; diff --git a/engine/client/snd_directx.c b/engine/client/snd_directx.c index e6cbc207..3b110032 100644 --- a/engine/client/snd_directx.c +++ b/engine/client/snd_directx.c @@ -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) diff --git a/engine/client/snd_win.c b/engine/client/snd_win.c index 3391757d..fc6536f5 100644 --- a/engine/client/snd_win.c +++ b/engine/client/snd_win.c @@ -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; diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 28d50f47..a0e31b90 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -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 diff --git a/engine/common/fs.c b/engine/common/fs.c index e6b6ae0e..d4412885 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -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 diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index d10986b4..9bd1fea2 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -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)<lmshift; out->extents[1] = (LittleLong(in->lightmap_height)-1)<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); - loadmodel->lightdatasize = 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++]; - } - - if (r_lightmap_saturation.value != 1.0f) - SaturateR8G8B8(out - mapsize, mapsize, r_lightmap_saturation.value); - } } - - if (loadmodel->lightdata) + for (; m%loadmodel->lightmaps.merge; m++) { - 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 = 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+=3) + { + 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); diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index c8afb04a..261b7b86 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -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; diff --git a/engine/common/plugin.c b/engine/common/plugin.c index 7de0dd22..aa0d4a2d 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -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) diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 0558c6c3..f9ba21f6 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -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; diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index 972e6732..24a7757f 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -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); diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index 5f96005b..a91b2d50 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -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; diff --git a/engine/d3d/d3d11_backend.c b/engine/d3d/d3d11_backend.c index 9e77c4c0..1869b0fb 100644 --- a/engine/d3d/d3d11_backend.c +++ b/engine/d3d/d3d11_backend.c @@ -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) { diff --git a/engine/d3d/d3d11_shader.c b/engine/d3d/d3d11_shader.c index 9992d15d..510e3f61 100644 --- a/engine/d3d/d3d11_shader.c +++ b/engine/d3d/d3d11_shader.c @@ -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) { diff --git a/engine/dotnet2005/ftequake.sln b/engine/dotnet2005/ftequake.sln index c714dd3f..4372c49c 100644 --- a/engine/dotnet2005/ftequake.sln +++ b/engine/dotnet2005/ftequake.sln @@ -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 diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index a29ec231..45e708b7 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -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,16 +4184,30 @@ static void DrawMeshes(void) break; case BEM_GBUFFER: altshader = shaderstate.curshader->bemoverrides[bemoverride_gbuffer]; - if (altshader && altshader->prog) + if (altshader) { - 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->prog); + if (altshader->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->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); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + 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); } diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index 528ae5bb..2beadb77 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -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: diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 74b9ca89..fe4dc99b 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -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,19 +2504,25 @@ 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) + for (sty = 0; sty < MAXRLIGHTMAPS; sty++) { - if (mesh->lmst_array[sty]) + if (surf->lightmaptexturenums[sty] >= 0) { - for (i = 0; i < mesh->numvertexes; i++) + if (mod->lightmaps.deluxemapping) + surf->lightmaptexturenums[sty] /= 2; + if (mesh->lmst_array[sty]) { - mesh->lmst_array[sty][i][1] += surf->lightmaptexturenums[sty] % lmmerge; - mesh->lmst_array[sty][i][1] /= lmmerge; + for (i = 0; i < mesh->numvertexes; i++) + { + mesh->lmst_array[sty][i][1] += surf->lightmaptexturenums[sty] % lmmerge; + mesh->lmst_array[sty][i][1] /= lmmerge; + } } + surf->lightmaptexturenums[sty] /= lmmerge; + if (mod->lightmaps.deluxemapping) + surf->lightmaptexturenums[sty] *= 2; } - surf->lightmaptexturenums[sty] /= lmmerge; } } } @@ -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); } diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index b4ab192c..f87c893d 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -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; diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index bdfecf1d..87623e72 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -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" - "program lpp_light\n" + "deferredlight\n" + "surfaceparm nodlight\n" "{\n" - "map $sourcecolour\n" + "program lpp_light\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; diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index fe5b6025..30485556 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -1350,7 +1350,10 @@ 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). - qglClear (GL_DEPTH_BUFFER_BIT); + if (fbo && r_clear.ival) + qglClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + else + qglClear (GL_DEPTH_BUFFER_BIT); } if (!fbo) depthcleared = false; @@ -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); diff --git a/engine/gl/gl_rsurf.c b/engine/gl/gl_rsurf.c index fd49434e..1c788c0b 100644 --- a/engine/gl/gl_rsurf.c +++ b/engine/gl/gl_rsurf.c @@ -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); diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index b0dd8f18..1f390669 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -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,17 +105,14 @@ skipwhite: *data_p = NULL; return ""; } - if (c == '\n') - newlines = true; + if (c == '\n' && !nl) + { + *data_p = data; + return com_token; + } data++; } - if (newlines && !nl) - { - *data_p = data; - return com_token; - } - // 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,64 +2534,81 @@ 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"}, - {"glslprogram", Shader_GLSLProgramName, "fte"}, - {"program", Shader_ProgramName, "fte"}, //gl or d3d - {"hlslprogram", Shader_HLSL9ProgramName, "fte"}, //for d3d - {"hlsl11program", Shader_HLSL11ProgramName, "fte"}, //for d3d - {"param", Shader_ProgramParam, "fte"}, //legacy - {"affine", Shader_Affine, "fte"}, //some hardware is horribly slow, and can benefit from certain hints. + {"clutter", Shader_ClutterParms, "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 + {"hlsl11program", Shader_HLSL11ProgramName, "fte"}, //for d3d + {"param", Shader_ProgramParam, "fte"}, //legacy + {"affine", Shader_Affine, "fte"}, //some hardware is horribly slow, and can benefit from certain hints. - {"bemode", Shader_BEMode, "fte"}, + {"bemode", Shader_BEMode, "fte"}, - {"diffusemap", Shader_DiffuseMap, "fte"}, - {"normalmap", Shader_NormalMap, "fte"}, - {"specularmap", Shader_SpecularMap, "fte"}, - {"fullbrightmap", Shader_FullbrightMap, "fte"}, - {"uppermap", Shader_UpperMap, "fte"}, - {"lowermap", Shader_LowerMap, "fte"}, - {"reflectmask", Shader_ReflectMask, "fte"}, - - //dp compat - {"reflectcube", Shader_ReflectCube, "dp"}, - {"camera", Shader_DP_Camera, "dp"}, - {"water", Shader_DP_Water, "dp"}, - {"reflect", Shader_DP_Reflect, "dp"}, - {"refract", Shader_DP_Refract, "dp"}, - {"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) - - /*doom3 compat*/ - {"diffusemap", Shader_DiffuseMap, "doom3"}, //macro for "{\nstage diffusemap\nmap \n}" - {"bumpmap", Shader_NormalMap, "doom3"}, //macro for "{\nstage bumpmap\nmap \n}" - {"discrete", NULL, "doom3"}, - {"nonsolid", NULL, "doom3"}, - {"noimpact", NULL, "doom3"}, - {"translucent", Shader_Translucent, "doom3"}, - {"noshadows", NULL, "doom3"}, - {"nooverlays", NULL, "doom3"}, - {"nofragment", NULL, "doom3"}, + {"diffusemap", Shader_DiffuseMap, "fte"}, + {"normalmap", Shader_NormalMap, "fte"}, + {"specularmap", Shader_SpecularMap, "fte"}, + {"fullbrightmap", Shader_FullbrightMap, "fte"}, + {"uppermap", Shader_UpperMap, "fte"}, + {"lowermap", Shader_LowerMap, "fte"}, + {"reflectmask", Shader_ReflectMask, "fte"}, /*simpler parsing for fte shaders*/ - {"progblendfunc", Shader_ProgBlendFunc, "fte"}, - {"progmap", Shader_ProgMap, "fte"}, + {"progblendfunc", Shader_ProgBlendFunc, "fte"}, + {"progmap", Shader_ProgMap, "fte"}, + + //dp compat + {"reflectcube", Shader_ReflectCube, "dp"}, + {"camera", Shader_DP_Camera, "dp"}, + {"water", Shader_DP_Water, "dp"}, + {"reflect", Shader_DP_Reflect, "dp"}, + {"refract", Shader_DP_Refract, "dp"}, + {"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) + + /*doom3 compat*/ + {"diffusemap", Shader_DiffuseMap, "doom3"}, //macro for "{\nstage diffusemap\nmap \n}" + {"bumpmap", Shader_NormalMap, "doom3"}, //macro for "{\nstage bumpmap\nmap \n}" + {"discrete", NULL, "doom3"}, + {"nonsolid", NULL, "doom3"}, + {"noimpact", NULL, "doom3"}, + {"translucent", Shader_Translucent, "doom3"}, + {"noshadows", NULL, "doom3"}, + {"nooverlays", NULL, "doom3"}, + {"nofragment", NULL, "doom3"}, + + /*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,30 +3535,34 @@ 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"}, - + /*doom3 compat*/ {"blend", Shaderpass_BlendFunc, "doom3"}, {"maskcolor", Shaderpass_MaskColor, "doom3"}, @@ -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); } @@ -6718,20 +6844,20 @@ char *Shader_Decompose(shader_t *s) switch (s->sort) { - 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_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_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_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; - default: sprintf(o, "sort %i\n", s->sort); break; + 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_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_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_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; + default: sprintf(o, "sort %i\n", s->sort); break; } o+=strlen(o); diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index 2cb7b298..e09d9e3b 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -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; - clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin); - lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST); +// 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; - 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, 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; } } diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index c780020c..460fee1a 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -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; diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index 0830657a..b70ee162 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -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; diff --git a/engine/gl/gl_warp.c b/engine/gl/gl_warp.c index 11dcb0d0..7e17c58b 100644 --- a/engine/gl/gl_warp.c +++ b/engine/gl/gl_warp.c @@ -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. - R_DrawFastSky(batch); - return true; //depth will always be drawn with this pathway. - }*/ + 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... 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. diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index 473eb209..8302c27c 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -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*/ diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 422092b4..c6ed1d9f 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -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 diff --git a/engine/qclib/decomp.c b/engine/qclib/decomp.c index cb107612..85ceb5b6 100644 --- a/engine/qclib/decomp.c +++ b/engine/qclib/decomp.c @@ -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", "DONE", -1, ASSOC_LEFT, &type_void, &type_void, &type_void}, + {6, "", "DONE", PC_NONE, ASSOC_LEFT, &type_void, &type_void, &type_void}, - {6, "*", "MUL_F", 3, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {6, "*", "MUL_V", 3, ASSOC_LEFT, &type_vector, &type_vector, &type_float}, - {6, "*", "MUL_FV", 3, ASSOC_LEFT, &type_float, &type_vector, &type_vector}, - {6, "*", "MUL_VF", 3, ASSOC_LEFT, &type_vector, &type_float, &type_vector}, + {6, "*", "MUL_F", PC_MULDIV, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {6, "*", "MUL_V", PC_MULDIV, ASSOC_LEFT, &type_vector, &type_vector, &type_float}, + {6, "*", "MUL_FV", PC_MULDIV, ASSOC_LEFT, &type_float, &type_vector, &type_vector}, + {6, "*", "MUL_VF", PC_MULDIV, ASSOC_LEFT, &type_vector, &type_float, &type_vector}, - {6, "/", "DIV_F", 3, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {6, "/", "DIV_F", PC_MULDIV, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {6, "+", "ADD_F", 4, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {6, "+", "ADD_V", 4, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, + {6, "+", "ADD_F", PC_ADDSUB, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {6, "+", "ADD_V", PC_ADDSUB, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, - {6, "-", "SUB_F", 4, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {6, "-", "SUB_V", 4, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, + {6, "-", "SUB_F", PC_ADDSUB, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {6, "-", "SUB_V", PC_ADDSUB, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, - {6, "==", "EQ_F", 5, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {6, "==", "EQ_V", 5, ASSOC_LEFT, &type_vector, &type_vector, &type_float}, - {6, "==", "EQ_S", 5, ASSOC_LEFT, &type_string, &type_string, &type_float}, - {6, "==", "EQ_E", 5, ASSOC_LEFT, &type_entity, &type_entity, &type_float}, - {6, "==", "EQ_FNC", 5, ASSOC_LEFT, &type_function, &type_function, &type_float}, + {6, "==", "EQ_F", PC_EQUALITY, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {6, "==", "EQ_V", PC_EQUALITY, ASSOC_LEFT, &type_vector, &type_vector, &type_float}, + {6, "==", "EQ_S", PC_EQUALITY, ASSOC_LEFT, &type_string, &type_string, &type_float}, + {6, "==", "EQ_E", PC_EQUALITY, ASSOC_LEFT, &type_entity, &type_entity, &type_float}, + {6, "==", "EQ_FNC", PC_EQUALITY, ASSOC_LEFT, &type_function, &type_function, &type_float}, - {6, "!=", "NE_F", 5, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {6, "!=", "NE_V", 5, ASSOC_LEFT, &type_vector, &type_vector, &type_float}, - {6, "!=", "NE_S", 5, ASSOC_LEFT, &type_string, &type_string, &type_float}, - {6, "!=", "NE_E", 5, ASSOC_LEFT, &type_entity, &type_entity, &type_float}, - {6, "!=", "NE_FNC", 5, ASSOC_LEFT, &type_function, &type_function, &type_float}, + {6, "!=", "NE_F", PC_EQUALITY, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {6, "!=", "NE_V", PC_EQUALITY, ASSOC_LEFT, &type_vector, &type_vector, &type_float}, + {6, "!=", "NE_S", PC_EQUALITY, ASSOC_LEFT, &type_string, &type_string, &type_float}, + {6, "!=", "NE_E", PC_EQUALITY, ASSOC_LEFT, &type_entity, &type_entity, &type_float}, + {6, "!=", "NE_FNC", PC_EQUALITY, ASSOC_LEFT, &type_function, &type_function, &type_float}, - {6, "<=", "LE_F", 5, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {6, ">=", "GE_F", 5, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {6, "<", "LT_F", 5, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {6, ">", "GT_F", 5, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {6, "<=", "LE_F", PC_RELATION, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {6, ">=", "GE_F", PC_RELATION, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {6, "<", "LT_F", PC_RELATION, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {6, ">", "GT_F", PC_RELATION, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {6, ".", "LOADF_F", 1, ASSOC_LEFT, &type_entity, &type_field, &type_float}, - {6, ".", "LOADF_V", 1, ASSOC_LEFT, &type_entity, &type_field, &type_vector}, - {6, ".", "LOADF_S", 1, ASSOC_LEFT, &type_entity, &type_field, &type_string}, - {6, ".", "LOADF_E", 1, ASSOC_LEFT, &type_entity, &type_field, &type_entity}, - {6, ".", "LOADF_FI", 1, ASSOC_LEFT, &type_entity, &type_field, &type_field}, - {6, ".", "LOADF_FU", 1, ASSOC_LEFT, &type_entity, &type_field, &type_function}, + {6, ".", "LOADF_F", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_float}, + {6, ".", "LOADF_V", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_vector}, + {6, ".", "LOADF_S", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_string}, + {6, ".", "LOADF_E", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_entity}, + {6, ".", "LOADF_FI", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_field}, + {6, ".", "LOADF_FU", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_function}, - {6, ".", "FLDADDRESS", 1, ASSOC_LEFT, &type_entity, &type_field, &type_pointer}, + {6, ".", "FLDADDRESS", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_pointer}, - {6, "=", "STORE_F", 6, ASSOC_RIGHT, &type_float, &type_float, &type_float}, - {6, "=", "STORE_V", 6, ASSOC_RIGHT, &type_vector, &type_vector, &type_vector}, - {6, "=", "STORE_S", 6, ASSOC_RIGHT, &type_string, &type_string, &type_string}, - {6, "=", "STORE_ENT", 6, ASSOC_RIGHT, &type_entity, &type_entity, &type_entity}, - {6, "=", "STORE_FLD", 6, ASSOC_RIGHT, &type_field, &type_field, &type_field}, - {6, "=", "STORE_FNC", 6, ASSOC_RIGHT, &type_function, &type_function, &type_function}, + {6, "=", "STORE_F", PC_STORE, ASSOC_RIGHT, &type_float, &type_float, &type_float}, + {6, "=", "STORE_V", PC_STORE, ASSOC_RIGHT, &type_vector, &type_vector, &type_vector}, + {6, "=", "STORE_S", PC_STORE, ASSOC_RIGHT, &type_string, &type_string, &type_string}, + {6, "=", "STORE_ENT", PC_STORE, ASSOC_RIGHT, &type_entity, &type_entity, &type_entity}, + {6, "=", "STORE_FLD", PC_STORE, ASSOC_RIGHT, &type_field, &type_field, &type_field}, + {6, "=", "STORE_FNC", PC_STORE, ASSOC_RIGHT, &type_function, &type_function, &type_function}, - {6, "=", "STOREP_F", 6, ASSOC_RIGHT, &type_pointer, &type_float, &type_float}, - {6, "=", "STOREP_V", 6, ASSOC_RIGHT, &type_pointer, &type_vector, &type_vector}, - {6, "=", "STOREP_S", 6, ASSOC_RIGHT, &type_pointer, &type_string, &type_string}, - {6, "=", "STOREP_ENT", 6, ASSOC_RIGHT, &type_pointer, &type_entity, &type_entity}, - {6, "=", "STOREP_FLD", 6, ASSOC_RIGHT, &type_pointer, &type_field, &type_field}, - {6, "=", "STOREP_FNC", 6, ASSOC_RIGHT, &type_pointer, &type_function, &type_function}, + {6, "=", "STOREP_F", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_float, &type_float}, + {6, "=", "STOREP_V", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_vector, &type_vector}, + {6, "=", "STOREP_S", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_string, &type_string}, + {6, "=", "STOREP_ENT", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_entity, &type_entity}, + {6, "=", "STOREP_FLD", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_field, &type_field}, + {6, "=", "STOREP_FNC", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_function, &type_function}, - {6, "", "RETURN", -1, ASSOC_LEFT, &type_vector, &type_void, &type_void}, + {6, "", "RETURN", PC_NONE, ASSOC_LEFT, &type_vector, &type_void, &type_void}, - {6, "!", "NOT_F", -1, ASSOC_LEFT, &type_float, &type_void, &type_float}, - {6, "!", "NOT_V", -1, ASSOC_LEFT, &type_vector, &type_void, &type_float}, - {6, "!", "NOT_S", -1, ASSOC_LEFT, &type_vector, &type_void, &type_float}, - {6, "!", "NOT_ENT", -1, ASSOC_LEFT, &type_entity, &type_void, &type_float}, - {6, "!", "NOT_FNC", -1, ASSOC_LEFT, &type_function, &type_void, &type_float}, + {6, "!", "NOT_F", PC_UNARY, ASSOC_LEFT, &type_float, &type_void, &type_float}, + {6, "!", "NOT_V", PC_UNARY, ASSOC_LEFT, &type_vector, &type_void, &type_float}, + {6, "!", "NOT_S", PC_UNARY, ASSOC_LEFT, &type_vector, &type_void, &type_float}, + {6, "!", "NOT_ENT", PC_UNARY, ASSOC_LEFT, &type_entity, &type_void, &type_float}, + {6, "!", "NOT_FNC", PC_UNARY, ASSOC_LEFT, &type_function, &type_void, &type_float}, - {6, "", "IF", -1, ASSOC_RIGHT, &type_float, NULL, &type_void}, - {6, "", "IFNOT", -1, ASSOC_RIGHT, &type_float, NULL, &type_void}, + {6, "", "IF", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void}, + {6, "", "IFNOT", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void}, // calls returns REG_RETURN - {6, "", "CALL0", -1, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "CALL1", -1, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "CALL2", -1, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "CALL3", -1, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "CALL4", -1, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "CALL5", -1, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "CALL6", -1, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "CALL7", -1, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "CALL8", -1, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL0", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL1", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL2", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL3", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL4", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL5", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL6", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL7", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, + {6, "", "CALL8", PC_NONE, ASSOC_LEFT, &type_function, &type_void, &type_void}, - {6, "", "STATE", -1, ASSOC_LEFT, &type_float, &type_float, &type_void}, + {6, "", "STATE", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_void}, - {6, "", "GOTO", -1, ASSOC_RIGHT, NULL, &type_void, &type_void}, + {6, "", "GOTO", PC_NONE, ASSOC_RIGHT, NULL, &type_void, &type_void}, - {6, "&&", "AND_F", 7, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {6, "||", "OR_F", 7, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {6, "&&", "AND_F", PC_LOGICAND, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {6, "||", "OR_F", PC_LOGICOR, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {6, "&", "BITAND", 3, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {6, "|", "BITOR", 3, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {6, "&", "BITAND", PC_BITAND, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {6, "|", "BITOR", PC_BITOR, ASSOC_LEFT, &type_float, &type_float, &type_float}, //version 6 are in normal progs. //these are hexen2 - {7, "*=", "MULSTORE_F", 6, ASSOC_RIGHT_RESULT, &type_float, &type_float, &type_float}, - {7, "*=", "MULSTORE_VF", 6, ASSOC_RIGHT_RESULT, &type_vector, &type_float, &type_vector}, - {7, "*=", "MULSTOREP_F", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_float}, - {7, "*=", "MULSTOREP_VF", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_vector}, + {7, "*=", "MULSTORE_F", PC_STORE, ASSOC_RIGHT_RESULT, &type_float, &type_float, &type_float}, + {7, "*=", "MULSTORE_VF", PC_STORE, ASSOC_RIGHT_RESULT, &type_vector, &type_float, &type_vector}, + {7, "*=", "MULSTOREP_F", PC_STORE, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_float}, + {7, "*=", "MULSTOREP_VF", PC_STORE, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_vector}, - {7, "/=", "DIVSTORE_F", 6, ASSOC_RIGHT_RESULT, &type_float, &type_float, &type_float}, - {7, "/=", "DIVSTOREP_F", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_float}, + {7, "/=", "DIVSTORE_F", PC_STORE, ASSOC_RIGHT_RESULT, &type_float, &type_float, &type_float}, + {7, "/=", "DIVSTOREP_F", PC_STORE, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_float}, - {7, "+=", "ADDSTORE_F", 6, ASSOC_RIGHT_RESULT, &type_float, &type_float, &type_float}, - {7, "+=", "ADDSTORE_V", 6, ASSOC_RIGHT_RESULT, &type_vector, &type_vector, &type_vector}, - {7, "+=", "ADDSTOREP_F", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_float}, - {7, "+=", "ADDSTOREP_V", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_vector, &type_vector}, + {7, "+=", "ADDSTORE_F", PC_STORE, ASSOC_RIGHT_RESULT, &type_float, &type_float, &type_float}, + {7, "+=", "ADDSTORE_V", PC_STORE, ASSOC_RIGHT_RESULT, &type_vector, &type_vector, &type_vector}, + {7, "+=", "ADDSTOREP_F", PC_STORE, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_float}, + {7, "+=", "ADDSTOREP_V", PC_STORE, ASSOC_RIGHT_RESULT, &type_pointer, &type_vector, &type_vector}, - {7, "-=", "SUBSTORE_F", 6, ASSOC_RIGHT_RESULT, &type_float, &type_float, &type_float}, - {7, "-=", "SUBSTORE_V", 6, ASSOC_RIGHT_RESULT, &type_vector, &type_vector, &type_vector}, - {7, "-=", "SUBSTOREP_F", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_float}, - {7, "-=", "SUBSTOREP_V", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_vector, &type_vector}, + {7, "-=", "SUBSTORE_F", PC_STORE, ASSOC_RIGHT_RESULT, &type_float, &type_float, &type_float}, + {7, "-=", "SUBSTORE_V", PC_STORE, ASSOC_RIGHT_RESULT, &type_vector, &type_vector, &type_vector}, + {7, "-=", "SUBSTOREP_F", PC_STORE, ASSOC_RIGHT_RESULT, &type_pointer, &type_float, &type_float}, + {7, "-=", "SUBSTOREP_V", PC_STORE, ASSOC_RIGHT_RESULT, &type_pointer, &type_vector, &type_vector}, - {7, "", "FETCH_GBL_F", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {7, "", "FETCH_GBL_V", -1, ASSOC_LEFT, &type_vector, &type_float, &type_vector}, - {7, "", "FETCH_GBL_S", -1, ASSOC_LEFT, &type_string, &type_float, &type_string}, - {7, "", "FETCH_GBL_E", -1, ASSOC_LEFT, &type_entity, &type_float, &type_entity}, - {7, "", "FETCH_GBL_FNC", -1, ASSOC_LEFT, &type_function, &type_float, &type_function}, + {7, "", "FETCH_GBL_F", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {7, "", "FETCH_GBL_V", PC_NONE, ASSOC_LEFT, &type_vector, &type_float, &type_vector}, + {7, "", "FETCH_GBL_S", PC_NONE, ASSOC_LEFT, &type_string, &type_float, &type_string}, + {7, "", "FETCH_GBL_E", PC_NONE, ASSOC_LEFT, &type_entity, &type_float, &type_entity}, + {7, "", "FETCH_GBL_FNC", PC_NONE, ASSOC_LEFT, &type_function, &type_float, &type_function}, - {7, "", "CSTATE", -1, ASSOC_LEFT, &type_float, &type_float, &type_void}, + {7, "", "CSTATE", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_void}, - {7, "", "CWSTATE", -1, ASSOC_LEFT, &type_float, &type_float, &type_void}, + {7, "", "CWSTATE", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_void}, - {7, "", "THINKTIME", -1, ASSOC_LEFT, &type_entity, &type_float, &type_void}, + {7, "", "THINKTIME", PC_NONE, ASSOC_LEFT, &type_entity, &type_float, &type_void}, - {7, "|=", "BITSETSTORE_F", 6, ASSOC_RIGHT, &type_float, &type_float, &type_float}, - {7, "|=", "BITSETSTOREP_F", 6, ASSOC_RIGHT, &type_pointer, &type_float, &type_float}, - {7, "&~=", "BITCLRSTORE_F", 6, ASSOC_RIGHT, &type_float, &type_float, &type_float}, - {7, "&~=", "BITCLRSTOREP_F", 6, ASSOC_RIGHT, &type_pointer, &type_float, &type_float}, + {7, "|=", "BITSETSTORE_F", PC_STORE, ASSOC_RIGHT, &type_float, &type_float, &type_float}, + {7, "|=", "BITSETSTOREP_F", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_float, &type_float}, + {7, "&~=", "BITCLRSTORE_F", PC_STORE, ASSOC_RIGHT, &type_float, &type_float, &type_float}, + {7, "&~=", "BITCLRSTOREP_F", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_float, &type_float}, - {7, "", "RAND0", -1, ASSOC_LEFT, &type_void, &type_void, &type_float}, - {7, "", "RAND1", -1, ASSOC_LEFT, &type_float, &type_void, &type_float}, - {7, "", "RAND2", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {7, "", "RANDV0", -1, ASSOC_LEFT, &type_void, &type_void, &type_vector}, - {7, "", "RANDV1", -1, ASSOC_LEFT, &type_vector, &type_void, &type_vector}, - {7, "", "RANDV2", -1, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, + {7, "", "RAND0", PC_NONE, ASSOC_LEFT, &type_void, &type_void, &type_float}, + {7, "", "RAND1", PC_NONE, ASSOC_LEFT, &type_float, &type_void, &type_float}, + {7, "", "RAND2", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {7, "", "RANDV0", PC_NONE, ASSOC_LEFT, &type_void, &type_void, &type_vector}, + {7, "", "RANDV1", PC_NONE, ASSOC_LEFT, &type_vector, &type_void, &type_vector}, + {7, "", "RANDV2", PC_NONE, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, - {7, "", "SWITCH_F", -1, ASSOC_RIGHT, &type_float, NULL, &type_void}, - {7, "", "SWITCH_V", -1, ASSOC_RIGHT, &type_vector, NULL, &type_void}, - {7, "", "SWITCH_S", -1, ASSOC_RIGHT, &type_string, NULL, &type_void}, - {7, "", "SWITCH_E", -1, ASSOC_RIGHT, &type_entity, NULL, &type_void}, - {7, "", "SWITCH_FNC", -1, ASSOC_RIGHT, &type_function, NULL, &type_void}, + {7, "", "SWITCH_F", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void}, + {7, "", "SWITCH_V", PC_NONE, ASSOC_RIGHT, &type_vector, NULL, &type_void}, + {7, "", "SWITCH_S", PC_NONE, ASSOC_RIGHT, &type_string, NULL, &type_void}, + {7, "", "SWITCH_E", PC_NONE, ASSOC_RIGHT, &type_entity, NULL, &type_void}, + {7, "", "SWITCH_FNC", PC_NONE, ASSOC_RIGHT, &type_function, NULL, &type_void}, - {7, "", "CASE", -1, ASSOC_RIGHT, &type_variant, NULL, &type_void}, - {7, "", "CASERANGE", -1, ASSOC_RIGHT, &type_float, &type_float, NULL}, + {7, "", "CASE", PC_NONE, ASSOC_RIGHT, &type_variant, NULL, &type_void}, + {7, "", "CASERANGE", PC_NONE, ASSOC_RIGHT, &type_float, &type_float, NULL}, //Later are additions by DMW. - {7, "", "CALL1H", -1, ASSOC_RIGHT, &type_function, &type_variant, &type_void}, - {7, "", "CALL2H", -1, ASSOC_RIGHT, &type_function, &type_variant, &type_variant}, - {7, "", "CALL3H", -1, ASSOC_RIGHT, &type_function, &type_variant, &type_variant}, - {7, "", "CALL4H", -1, ASSOC_RIGHT, &type_function, &type_variant, &type_variant}, - {7, "", "CALL5H", -1, ASSOC_RIGHT, &type_function, &type_variant, &type_variant}, - {7, "", "CALL6H", -1, ASSOC_RIGHT, &type_function, &type_variant, &type_variant}, - {7, "", "CALL7H", -1, ASSOC_RIGHT, &type_function, &type_variant, &type_variant}, - {7, "", "CALL8H", -1, ASSOC_RIGHT, &type_function, &type_variant, &type_variant}, + {7, "", "CALL1H", PC_NONE, ASSOC_RIGHT, &type_function, &type_variant, &type_void}, + {7, "", "CALL2H", PC_NONE, ASSOC_RIGHT, &type_function, &type_variant, &type_variant}, + {7, "", "CALL3H", PC_NONE, ASSOC_RIGHT, &type_function, &type_variant, &type_variant}, + {7, "", "CALL4H", PC_NONE, ASSOC_RIGHT, &type_function, &type_variant, &type_variant}, + {7, "", "CALL5H", PC_NONE, ASSOC_RIGHT, &type_function, &type_variant, &type_variant}, + {7, "", "CALL6H", PC_NONE, ASSOC_RIGHT, &type_function, &type_variant, &type_variant}, + {7, "", "CALL7H", PC_NONE, ASSOC_RIGHT, &type_function, &type_variant, &type_variant}, + {7, "", "CALL8H", PC_NONE, ASSOC_RIGHT, &type_function, &type_variant, &type_variant}, - {7, "=", "STORE_I", 6, ASSOC_RIGHT, &type_integer, &type_integer, &type_integer}, - {7, "=", "STORE_IF", 6, ASSOC_RIGHT, &type_float, &type_integer, &type_integer}, - {7, "=", "STORE_FI", 6, ASSOC_RIGHT, &type_integer, &type_float, &type_float}, + {7, "=", "STORE_I", PC_STORE, ASSOC_RIGHT, &type_integer, &type_integer, &type_integer}, + {7, "=", "STORE_IF", PC_STORE, ASSOC_RIGHT, &type_float, &type_integer, &type_integer}, + {7, "=", "STORE_FI", PC_STORE, ASSOC_RIGHT, &type_integer, &type_float, &type_float}, - {7, "+", "ADD_I", 4, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, "+", "ADD_FI", 4, ASSOC_LEFT, &type_float, &type_integer, &type_float}, - {7, "+", "ADD_IF", 4, ASSOC_LEFT, &type_integer, &type_float, &type_float}, + {7, "+", "ADD_I", PC_ADDSUB, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, "+", "ADD_FI", PC_ADDSUB, ASSOC_LEFT, &type_float, &type_integer, &type_float}, + {7, "+", "ADD_IF", PC_ADDSUB, ASSOC_LEFT, &type_integer, &type_float, &type_float}, - {7, "-", "SUB_I", 4, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, "-", "SUB_FI", 4, ASSOC_LEFT, &type_float, &type_integer, &type_float}, - {7, "-", "SUB_IF", 4, ASSOC_LEFT, &type_integer, &type_float, &type_float}, + {7, "-", "SUB_I", PC_ADDSUB, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, "-", "SUB_FI", PC_ADDSUB, ASSOC_LEFT, &type_float, &type_integer, &type_float}, + {7, "-", "SUB_IF", PC_ADDSUB, ASSOC_LEFT, &type_integer, &type_float, &type_float}, - {7, "", "C_ITOF", -1, ASSOC_LEFT, &type_integer, &type_void, &type_float}, - {7, "", "C_FTOI", -1, ASSOC_LEFT, &type_float, &type_void, &type_integer}, - {7, "", "CP_ITOF", -1, ASSOC_LEFT, &type_pointer, &type_integer, &type_float}, - {7, "", "CP_FTOI", -1, ASSOC_LEFT, &type_pointer, &type_float, &type_integer}, + {7, "", "C_ITOF", PC_STORE, ASSOC_LEFT, &type_integer, &type_void, &type_float}, + {7, "", "C_FTOI", PC_STORE, ASSOC_LEFT, &type_float, &type_void, &type_integer}, + {7, "", "CP_ITOF", PC_STORE, ASSOC_LEFT, &type_pointer, &type_integer, &type_float}, + {7, "", "CP_FTOI", PC_STORE, ASSOC_LEFT, &type_pointer, &type_float, &type_integer}, - {7, ".", "LOADF_I", 1, ASSOC_LEFT, &type_entity, &type_field, &type_integer}, - {7, "=", "STOREP_I", 6, ASSOC_RIGHT, &type_pointer, &type_integer, &type_integer}, - {7, "=", "STOREP_IF", 6, ASSOC_RIGHT, &type_pointer, &type_float, &type_integer}, - {7, "=", "STOREP_FI", 6, ASSOC_RIGHT, &type_pointer, &type_integer, &type_float}, + {7, ".", "LOADF_I", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_integer}, + {7, "=", "STOREP_I", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_integer, &type_integer}, + {7, "=", "STOREP_IF", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_float, &type_integer}, + {7, "=", "STOREP_FI", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_integer, &type_float}, - {7, "&", "BITAND_I", 3, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, "|", "BITOR_I", 3, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, "&", "BITAND_I", PC_BITAND, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, "|", "BITOR_I", PC_BITOR, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, "*", "MUL_I", 3, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, "/", "DIV_I", 3, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, "==", "EQ_I", 5, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, "!=", "NE_I", 5, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, "*", "MUL_I", PC_MULDIV, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, "/", "DIV_I", PC_MULDIV, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, "==", "EQ_I", PC_EQUALITY, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, "!=", "NE_I", PC_EQUALITY, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, "", "IFNOTS", -1, ASSOC_RIGHT, &type_string, NULL, &type_void}, - {7, "", "IFS", -1, ASSOC_RIGHT, &type_string, NULL, &type_void}, + {7, "", "IFNOTS", PC_NONE, ASSOC_RIGHT, &type_string, NULL, &type_void}, + {7, "", "IFS", PC_NONE, ASSOC_RIGHT, &type_string, NULL, &type_void}, - {7, "!", "NOT_I", -1, ASSOC_LEFT, &type_integer, &type_void, &type_integer}, + {7, "!", "NOT_I", PC_UNARY, ASSOC_LEFT, &type_integer, &type_void, &type_integer}, - {7, "/", "DIV_VF", 3, ASSOC_LEFT, &type_vector, &type_float, &type_vector}, + {7, "/", "DIV_VF", PC_MULDIV, ASSOC_LEFT, &type_vector, &type_float, &type_vector}, - {7, "^", "BITXOR_I", 3, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, ">>", "RSHIFT_I", 3, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, "<<", "LSHIFT_I", 3, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, "^", "BITXOR_I", PC_BITXOR, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, ">>", "RSHIFT_I", PC_SHIFT, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, "<<", "LSHIFT_I", PC_SHIFT, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, //var, offset return - {7, "", "GLOBALADDRESS", -1, ASSOC_LEFT, &type_float, &type_integer, &type_pointer}, - {7, "", "ADD_PIW", -1, ASSOC_LEFT, &type_pointer, &type_integer, &type_pointer}, + {7, "", "GLOBALADDRESS", PC_NONE, ASSOC_LEFT, &type_float, &type_integer, &type_pointer}, + {7, "", "ADD_PIW", PC_NONE, ASSOC_LEFT, &type_pointer, &type_integer, &type_pointer}, - {7, "=", "LOADA_F", 6, ASSOC_LEFT, &type_float, &type_integer, &type_float}, - {7, "=", "LOADA_V", 6, ASSOC_LEFT, &type_vector, &type_integer, &type_vector}, - {7, "=", "LOADA_S", 6, ASSOC_LEFT, &type_string, &type_integer, &type_string}, - {7, "=", "LOADA_ENT", 6, ASSOC_LEFT, &type_entity, &type_integer, &type_entity}, - {7, "=", "LOADA_FLD", 6, ASSOC_LEFT, &type_field, &type_integer, &type_field}, - {7, "=", "LOADA_FNC", 6, ASSOC_LEFT, &type_function, &type_integer, &type_function}, - {7, "=", "LOADA_I", 6, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, "=", "LOADA_F", PC_STORE, ASSOC_LEFT, &type_float, &type_integer, &type_float}, + {7, "=", "LOADA_V", PC_STORE, ASSOC_LEFT, &type_vector, &type_integer, &type_vector}, + {7, "=", "LOADA_S", PC_STORE, ASSOC_LEFT, &type_string, &type_integer, &type_string}, + {7, "=", "LOADA_ENT", PC_STORE, ASSOC_LEFT, &type_entity, &type_integer, &type_entity}, + {7, "=", "LOADA_FLD", PC_STORE, ASSOC_LEFT, &type_field, &type_integer, &type_field}, + {7, "=", "LOADA_FNC", PC_STORE, ASSOC_LEFT, &type_function, &type_integer, &type_function}, + {7, "=", "LOADA_I", PC_STORE, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, "=", "STORE_P", 6, ASSOC_RIGHT, &type_pointer, &type_pointer, &type_void}, - {7, ".", "LOADF_P", 1, ASSOC_LEFT, &type_entity, &type_field, &type_pointer}, + {7, "=", "STORE_P", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_pointer, &type_void}, + {7, ".", "LOADF_P", PC_MEMBER, ASSOC_LEFT, &type_entity, &type_field, &type_pointer}, - {7, "=", "LOADP_F", 6, ASSOC_LEFT, &type_pointer, &type_integer, &type_float}, - {7, "=", "LOADP_V", 6, ASSOC_LEFT, &type_pointer, &type_integer, &type_vector}, - {7, "=", "LOADP_S", 6, ASSOC_LEFT, &type_pointer, &type_integer, &type_string}, - {7, "=", "LOADP_ENT", 6, ASSOC_LEFT, &type_pointer, &type_integer, &type_entity}, - {7, "=", "LOADP_FLD", 6, ASSOC_LEFT, &type_pointer, &type_integer, &type_field}, - {7, "=", "LOADP_FNC", 6, ASSOC_LEFT, &type_pointer, &type_integer, &type_function}, - {7, "=", "LOADP_I", 6, ASSOC_LEFT, &type_pointer, &type_integer, &type_integer}, + {7, "=", "LOADP_F", PC_STORE, ASSOC_LEFT, &type_pointer, &type_integer, &type_float}, + {7, "=", "LOADP_V", PC_STORE, ASSOC_LEFT, &type_pointer, &type_integer, &type_vector}, + {7, "=", "LOADP_S", PC_STORE, ASSOC_LEFT, &type_pointer, &type_integer, &type_string}, + {7, "=", "LOADP_ENT", PC_STORE, ASSOC_LEFT, &type_pointer, &type_integer, &type_entity}, + {7, "=", "LOADP_FLD", PC_STORE, ASSOC_LEFT, &type_pointer, &type_integer, &type_field}, + {7, "=", "LOADP_FNC", PC_STORE, ASSOC_LEFT, &type_pointer, &type_integer, &type_function}, + {7, "=", "LOADP_I", PC_STORE, ASSOC_LEFT, &type_pointer, &type_integer, &type_integer}, - {7, "<=", "LE_I", 5, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, ">=", "GE_I", 5, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, "<", "LT_I", 5, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, ">", "GT_I", 5, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, "<=", "LE_I", PC_RELATION, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, ">=", "GE_I", PC_RELATION, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, "<", "LT_I", PC_RELATION, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, ">", "GT_I", PC_RELATION, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, "<=", "LE_IF", 5, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, - {7, ">=", "GE_IF", 5, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, - {7, "<", "LT_IF", 5, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, - {7, ">", "GT_IF", 5, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, + {7, "<=", "LE_IF", PC_RELATION, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, + {7, ">=", "GE_IF", PC_RELATION, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, + {7, "<", "LT_IF", PC_RELATION, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, + {7, ">", "GT_IF", PC_RELATION, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, - {7, "<=", "LE_FI", 5, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, - {7, ">=", "GE_FI", 5, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, - {7, "<", "LT_FI", 5, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, - {7, ">", "GT_FI", 5, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, + {7, "<=", "LE_FI", PC_RELATION, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, + {7, ">=", "GE_FI", PC_RELATION, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, + {7, "<", "LT_FI", PC_RELATION, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, + {7, ">", "GT_FI", PC_RELATION, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, - {7, "==", "EQ_IF", 5, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, - {7, "==", "EQ_FI", 5, ASSOC_LEFT, &type_float, &type_integer, &type_float}, + {7, "==", "EQ_IF", PC_EQUALITY, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, + {7, "==", "EQ_FI", PC_EQUALITY, ASSOC_LEFT, &type_float, &type_integer, &type_float}, //------------------------------------- //string manipulation. - {7, "+", "ADD_SF", 4, ASSOC_LEFT, &type_string, &type_float, &type_string}, - {7, "-", "SUB_S", 4, ASSOC_LEFT, &type_string, &type_string, &type_float}, - {7, "", "STOREP_C", 1, ASSOC_RIGHT, &type_string, &type_float, &type_float}, - {7, "", "LOADP_C", 1, ASSOC_LEFT, &type_string, &type_float, &type_float}, + {7, "+", "ADD_SF", PC_ADDSUB, ASSOC_LEFT, &type_string, &type_float, &type_string}, + {7, "-", "SUB_S", PC_ADDSUB, ASSOC_LEFT, &type_string, &type_string, &type_float}, + {7, "", "STOREP_C", PC_STORE, ASSOC_RIGHT, &type_string, &type_float, &type_float}, + {7, "", "LOADP_C", PC_STORE, ASSOC_LEFT, &type_string, &type_float, &type_float}, //------------------------------------- -{7, "*", "MUL_IF", 5, ASSOC_LEFT, &type_integer, &type_float, &type_float}, -{7, "*", "MUL_FI", 5, ASSOC_LEFT, &type_float, &type_integer, &type_float}, -{7, "*", "MUL_VI", 5, ASSOC_LEFT, &type_vector, &type_integer, &type_vector}, -{7, "*", "MUL_IV", 5, ASSOC_LEFT, &type_integer, &type_vector, &type_vector}, +{7, "*", "MUL_IF", PC_MULDIV, ASSOC_LEFT, &type_integer, &type_float, &type_float}, +{7, "*", "MUL_FI", PC_MULDIV, ASSOC_LEFT, &type_float, &type_integer, &type_float}, +{7, "*", "MUL_VI", PC_MULDIV, ASSOC_LEFT, &type_vector, &type_integer, &type_vector}, +{7, "*", "MUL_IV", PC_MULDIV, ASSOC_LEFT, &type_integer, &type_vector, &type_vector}, -{7, "/", "DIV_IF", 5, ASSOC_LEFT, &type_integer, &type_float, &type_float}, -{7, "/", "DIV_FI", 5, ASSOC_LEFT, &type_float, &type_integer, &type_float}, +{7, "/", "DIV_IF", PC_MULDIV, ASSOC_LEFT, &type_integer, &type_float, &type_float}, +{7, "/", "DIV_FI", PC_MULDIV, ASSOC_LEFT, &type_float, &type_integer, &type_float}, -{7, "&", "BITAND_IF", 5, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, -{7, "|", "BITOR_IF", 5, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, -{7, "&", "BITAND_FI", 5, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, -{7, "|", "BITOR_FI", 5, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, +{7, "&", "BITAND_IF", PC_BITAND, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, +{7, "|", "BITOR_IF", PC_BITOR, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, +{7, "&", "BITAND_FI", PC_BITAND, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, +{7, "|", "BITOR_FI", PC_BITOR, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, -{7, "&&", "AND_I", 7, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, -{7, "||", "OR_I", 7, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, -{7, "&&", "AND_IF", 7, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, -{7, "||", "OR_IF", 7, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, -{7, "&&", "AND_FI", 7, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, -{7, "||", "OR_FI", 7, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, -{7, "!=", "NE_IF", 5, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, -{7, "!=", "NE_FI", 5, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, +{7, "&&", "AND_I", PC_LOGICAND, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, +{7, "||", "OR_I", PC_LOGICOR, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, +{7, "&&", "AND_IF", PC_LOGICAND, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, +{7, "||", "OR_IF", PC_LOGICOR, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, +{7, "&&", "AND_FI", PC_LOGICAND, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, +{7, "||", "OR_FI", PC_LOGICOR, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, +{7, "!=", "NE_IF", PC_EQUALITY, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, +{7, "!=", "NE_FI", PC_EQUALITY, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, -{7, "<>", "GSTOREP_I", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, -{7, "<>", "GSTOREP_F", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, -{7, "<>", "GSTOREP_ENT", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, -{7, "<>", "GSTOREP_FLD", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, -{7, "<>", "GSTOREP_S", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, -{7, "<>", "GSTOREP_FNC", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, -{7, "<>", "GSTOREP_V", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, +{7, "<>", "GSTOREP_I", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, +{7, "<>", "GSTOREP_F", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, +{7, "<>", "GSTOREP_ENT", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, +{7, "<>", "GSTOREP_FLD", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, +{7, "<>", "GSTOREP_S", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, +{7, "<>", "GSTOREP_FNC", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, +{7, "<>", "GSTOREP_V", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, -{7, "<>", "GADDRESS", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, +{7, "<>", "GADDRESS", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, -{7, "<>", "GLOAD_I", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, -{7, "<>", "GLOAD_F", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, -{7, "<>", "GLOAD_FLD", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, -{7, "<>", "GLOAD_ENT", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, -{7, "<>", "GLOAD_S", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, -{7, "<>", "GLOAD_FNC", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, +{7, "<>", "GLOAD_I", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, +{7, "<>", "GLOAD_F", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, +{7, "<>", "GLOAD_FLD", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, +{7, "<>", "GLOAD_ENT", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, +{7, "<>", "GLOAD_S", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, +{7, "<>", "GLOAD_FNC", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, -{7, "<>", "BOUNDCHECK", -1, ASSOC_LEFT, &type_integer, NULL, NULL}, +{7, "<>", "BOUNDCHECK", PC_NONE, ASSOC_LEFT, &type_integer, NULL, NULL}, -{7, "", "UNUSED", 6, ASSOC_RIGHT, &type_void, &type_void, &type_void}, -{7, "", "PUSH", -1, ASSOC_RIGHT, &type_float, &type_void, &type_pointer}, -{7, "", "POP", -1, ASSOC_RIGHT, &type_float, &type_void, &type_void}, +{7, "", "UNUSED", PC_NONE, ASSOC_RIGHT, &type_void, &type_void, &type_void}, +{7, "", "PUSH", PC_NONE, ASSOC_RIGHT, &type_float, &type_void, &type_pointer}, +{7, "", "POP", PC_NONE, ASSOC_RIGHT, &type_float, &type_void, &type_void}, -{7, "", "SWITCH_I", -1, ASSOC_LEFT, &type_void, NULL, &type_void}, -{7, "<>", "GLOAD_S", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, +{7, "", "SWITCH_I",PC_NONE, ASSOC_LEFT, &type_void, NULL, &type_void}, +{7, "<>", "GLOAD_S", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, -{7, "", "IF_F", -1, ASSOC_RIGHT, &type_float, NULL, &type_void}, -{7, "","IFNOT_F", -1, ASSOC_RIGHT, &type_float, NULL, &type_void}, +{7, "", "IF_F", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void}, +{7, "","IFNOT_F", PC_NONE, ASSOC_RIGHT, &type_float, NULL, &type_void}, /* -{7, "<=>", "STOREF_F", -1, ASSOC_RIGHT, &type_entity, &type_field, &type_float}, -{7, "<=>", "STOREF_V", -1, ASSOC_RIGHT, &type_entity, &type_field, &type_vector}, -{7, "<=>", "STOREF_IF", -1, ASSOC_RIGHT, &type_entity, &type_field, &type_float}, -{7, "<=>", "STOREF_FI", -1, ASSOC_RIGHT, &type_entity, &type_field, &type_float}, +{7, "<=>", "STOREF_F", PC_STORE, ASSOC_RIGHT, &type_entity, &type_field, &type_float}, +{7, "<=>", "STOREF_V", PC_STORE, ASSOC_RIGHT, &type_entity, &type_field, &type_vector}, +{7, "<=>", "STOREF_IF", PC_STORE, ASSOC_RIGHT, &type_entity, &type_field, &type_float}, +{7, "<=>", "STOREF_FI", PC_STORE, ASSOC_RIGHT, &type_entity, &type_field, &type_float}, */ /* emulated ops begin here */ - {7, "<>", "OP_EMULATED", -1, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {7, "<>", "OP_EMULATED", PC_NONE, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {7, "|=", "BITSET_I", 6, ASSOC_RIGHT_RESULT, &type_integer, &type_integer, &type_integer}, - {7, "|=", "BITSETP_I", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_integer}, - {7, "&~=", "BITCLR_I", 6, ASSOC_RIGHT_RESULT, &type_integer, &type_integer, &type_integer}, + {7, "|=", "BITSET_I", PC_STORE, ASSOC_RIGHT_RESULT, &type_integer, &type_integer, &type_integer}, + {7, "|=", "BITSETP_I", PC_STORE, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_integer}, + {7, "&~=", "BITCLR_I", PC_STORE, ASSOC_RIGHT_RESULT, &type_integer, &type_integer, &type_integer}, - {7, "*=", "MULSTORE_I", 6, ASSOC_RIGHT_RESULT, &type_integer, &type_integer, &type_integer}, - {7, "/=", "DIVSTORE_I", 6, ASSOC_RIGHT_RESULT, &type_integer, &type_integer, &type_integer}, - {7, "+=", "ADDSTORE_I", 6, ASSOC_RIGHT_RESULT, &type_integer, &type_integer, &type_integer}, - {7, "-=", "SUBSTORE_I", 6, ASSOC_RIGHT_RESULT, &type_integer, &type_integer, &type_integer}, + {7, "*=", "MULSTORE_I", PC_STORE, ASSOC_RIGHT_RESULT, &type_integer, &type_integer, &type_integer}, + {7, "/=", "DIVSTORE_I", PC_STORE, ASSOC_RIGHT_RESULT, &type_integer, &type_integer, &type_integer}, + {7, "+=", "ADDSTORE_I", PC_STORE, ASSOC_RIGHT_RESULT, &type_integer, &type_integer, &type_integer}, + {7, "-=", "SUBSTORE_I", PC_STORE, ASSOC_RIGHT_RESULT, &type_integer, &type_integer, &type_integer}, - {7, "*=", "MULSTOREP_I", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_integer}, - {7, "/=", "DIVSTOREP_I", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_integer}, - {7, "+=", "ADDSTOREP_I", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_integer}, - {7, "-=", "SUBSTOREP_I", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_integer}, + {7, "*=", "MULSTOREP_I", PC_STORE, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_integer}, + {7, "/=", "DIVSTOREP_I", PC_STORE, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_integer}, + {7, "+=", "ADDSTOREP_I", PC_STORE, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_integer}, + {7, "-=", "SUBSTOREP_I", PC_STORE, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_integer}, - {7, "*=", "MULSTORE_IF", 6, ASSOC_RIGHT_RESULT, &type_integer, &type_float, &type_float}, - {7, "*=", "MULSTOREP_IF", 6, ASSOC_RIGHT_RESULT, &type_intpointer, &type_float, &type_float}, - {7, "/=", "DIVSTORE_IF", 6, ASSOC_RIGHT_RESULT, &type_integer, &type_float, &type_float}, - {7, "/=", "DIVSTOREP_IF", 6, ASSOC_RIGHT_RESULT, &type_intpointer, &type_float, &type_float}, - {7, "+=", "ADDSTORE_IF", 6, ASSOC_RIGHT_RESULT, &type_integer, &type_float, &type_float}, - {7, "+=", "ADDSTOREP_IF", 6, ASSOC_RIGHT_RESULT, &type_intpointer, &type_float, &type_float}, - {7, "-=", "SUBSTORE_IF", 6, ASSOC_RIGHT_RESULT, &type_integer, &type_float, &type_float}, - {7, "-=", "SUBSTOREP_IF", 6, ASSOC_RIGHT_RESULT, &type_intpointer, &type_float, &type_float}, + {7, "*=", "MULSTORE_IF", PC_STORE, ASSOC_RIGHT_RESULT, &type_integer, &type_float, &type_float}, + {7, "*=", "MULSTOREP_IF", PC_STORE, ASSOC_RIGHT_RESULT, &type_intpointer, &type_float, &type_float}, + {7, "/=", "DIVSTORE_IF", PC_STORE, ASSOC_RIGHT_RESULT, &type_integer, &type_float, &type_float}, + {7, "/=", "DIVSTOREP_IF", PC_STORE, ASSOC_RIGHT_RESULT, &type_intpointer, &type_float, &type_float}, + {7, "+=", "ADDSTORE_IF", PC_STORE, ASSOC_RIGHT_RESULT, &type_integer, &type_float, &type_float}, + {7, "+=", "ADDSTOREP_IF", PC_STORE, ASSOC_RIGHT_RESULT, &type_intpointer, &type_float, &type_float}, + {7, "-=", "SUBSTORE_IF", PC_STORE, ASSOC_RIGHT_RESULT, &type_integer, &type_float, &type_float}, + {7, "-=", "SUBSTOREP_IF", PC_STORE, ASSOC_RIGHT_RESULT, &type_intpointer, &type_float, &type_float}, - {7, "*=", "MULSTORE_FI", 6, ASSOC_RIGHT_RESULT, &type_float, &type_integer, &type_float}, - {7, "*=", "MULSTOREP_FI", 6, ASSOC_RIGHT_RESULT, &type_floatpointer, &type_integer, &type_float}, - {7, "/=", "DIVSTORE_FI", 6, ASSOC_RIGHT_RESULT, &type_float, &type_integer, &type_float}, - {7, "/=", "DIVSTOREP_FI", 6, ASSOC_RIGHT_RESULT, &type_floatpointer, &type_integer, &type_float}, - {7, "+=", "ADDSTORE_FI", 6, ASSOC_RIGHT_RESULT, &type_float, &type_integer, &type_float}, - {7, "+=", "ADDSTOREP_FI", 6, ASSOC_RIGHT_RESULT, &type_floatpointer, &type_integer, &type_float}, - {7, "-=", "SUBSTORE_FI", 6, ASSOC_RIGHT_RESULT, &type_float, &type_integer, &type_float}, - {7, "-=", "SUBSTOREP_FI", 6, ASSOC_RIGHT_RESULT, &type_floatpointer, &type_integer, &type_float}, + {7, "*=", "MULSTORE_FI", PC_STORE, ASSOC_RIGHT_RESULT, &type_float, &type_integer, &type_float}, + {7, "*=", "MULSTOREP_FI", PC_STORE, ASSOC_RIGHT_RESULT, &type_floatpointer, &type_integer, &type_float}, + {7, "/=", "DIVSTORE_FI", PC_STORE, ASSOC_RIGHT_RESULT, &type_float, &type_integer, &type_float}, + {7, "/=", "DIVSTOREP_FI", PC_STORE, ASSOC_RIGHT_RESULT, &type_floatpointer, &type_integer, &type_float}, + {7, "+=", "ADDSTORE_FI", PC_STORE, ASSOC_RIGHT_RESULT, &type_float, &type_integer, &type_float}, + {7, "+=", "ADDSTOREP_FI", PC_STORE, ASSOC_RIGHT_RESULT, &type_floatpointer, &type_integer, &type_float}, + {7, "-=", "SUBSTORE_FI", PC_STORE, ASSOC_RIGHT_RESULT, &type_float, &type_integer, &type_float}, + {7, "-=", "SUBSTOREP_FI", PC_STORE, ASSOC_RIGHT_RESULT, &type_floatpointer, &type_integer, &type_float}, - {7, "*=", "MULSTORE_VI", 6, ASSOC_RIGHT_RESULT, &type_vector, &type_integer, &type_vector}, - {7, "*=", "MULSTOREP_VI", 6, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_vector}, + {7, "*=", "MULSTORE_VI", PC_STORE, ASSOC_RIGHT_RESULT, &type_vector, &type_integer, &type_vector}, + {7, "*=", "MULSTOREP_VI", PC_STORE, ASSOC_RIGHT_RESULT, &type_pointer, &type_integer, &type_vector}, - {7, "=", "LOADA_STRUCT", 6, ASSOC_LEFT, &type_float, &type_integer, &type_float}, + {7, "=", "LOADA_STRUCT", PC_STORE, ASSOC_LEFT, &type_float, &type_integer, &type_float}, - {7, "=", "LOADP_P", 6, ASSOC_LEFT, &type_pointer, &type_integer, &type_pointer}, - {7, "=", "STOREP_P", 6, ASSOC_RIGHT, &type_pointer, &type_pointer, &type_pointer}, - {7, "~", "BITNOT_F", -1, ASSOC_LEFT, &type_float, &type_void, &type_float}, - {7, "~", "BITNOT_I", -1, ASSOC_LEFT, &type_integer, &type_void, &type_integer}, + {7, "=", "LOADP_P", PC_STORE, ASSOC_LEFT, &type_pointer, &type_integer, &type_pointer}, + {7, "=", "STOREP_P", PC_STORE, ASSOC_RIGHT, &type_pointer, &type_pointer, &type_pointer}, + {7, "~", "BITNOT_F", PC_UNARY, ASSOC_LEFT, &type_float, &type_void, &type_float}, + {7, "~", "BITNOT_I", PC_UNARY, ASSOC_LEFT, &type_integer, &type_void, &type_integer}, - {7, "==", "EQ_P", 5, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float}, - {7, "!=", "NE_P", 5, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float}, - {7, "<=", "LE_P", 5, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float}, - {7, ">=", "GE_P", 5, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float}, - {7, "<", "LT_P", 5, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float}, - {7, ">", "GT_P", 5, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float}, + {7, "==", "EQ_P", PC_EQUALITY, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float}, + {7, "!=", "NE_P", PC_EQUALITY, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float}, + {7, "<=", "LE_P", PC_RELATION, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float}, + {7, ">=", "GE_P", PC_RELATION, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float}, + {7, "<", "LT_P", PC_RELATION, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float}, + {7, ">", "GT_P", PC_RELATION, ASSOC_LEFT, &type_pointer, &type_pointer, &type_float}, - {7, "&=", "ANDSTORE_F", 6, ASSOC_RIGHT_RESULT, &type_float, &type_float, &type_float}, - {7, "&~", "BITCLR_F", 6, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {7, "&~", "BITCLR_I", 6, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, "&=", "ANDSTORE_F", PC_STORE, ASSOC_RIGHT_RESULT, &type_float, &type_float, &type_float}, + {7, "&~=", "BITCLR_F", PC_STORE, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {7, "&~=", "BITCLR_I", PC_STORE, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, "+", "ADD_SI", 4, ASSOC_LEFT, &type_string, &type_integer, &type_string}, - {7, "+", "ADD_IS", 7, ASSOC_LEFT, &type_integer, &type_string, &type_string}, - {7, "+", "ADD_PF", 6, ASSOC_LEFT, &type_pointer, &type_float, &type_pointer}, - {7, "+", "ADD_FP", 6, ASSOC_LEFT, &type_float, &type_pointer, &type_pointer}, - {7, "+", "ADD_PI", 6, ASSOC_LEFT, &type_pointer, &type_integer, &type_pointer}, - {7, "+", "ADD_IP", 6, ASSOC_LEFT, &type_integer, &type_pointer, &type_pointer}, - {7, "-", "SUB_SI", 7, ASSOC_LEFT, &type_string, &type_integer, &type_string}, - {7, "-", "SUB_PF", 6, ASSOC_LEFT, &type_pointer, &type_float, &type_pointer}, - {7, "-", "SUB_PI", 6, ASSOC_LEFT, &type_pointer, &type_integer, &type_pointer}, - {7, "-", "SUB_PP", 6, ASSOC_LEFT, &type_pointer, &type_pointer, &type_integer}, + {7, "+", "ADD_SI", PC_ADDSUB, ASSOC_LEFT, &type_string, &type_integer, &type_string}, + {7, "+", "ADD_IS", PC_ADDSUB, ASSOC_LEFT, &type_integer, &type_string, &type_string}, + {7, "+", "ADD_PF", PC_ADDSUB, ASSOC_LEFT, &type_pointer, &type_float, &type_pointer}, + {7, "+", "ADD_FP", PC_ADDSUB, ASSOC_LEFT, &type_float, &type_pointer, &type_pointer}, + {7, "+", "ADD_PI", PC_ADDSUB, ASSOC_LEFT, &type_pointer, &type_integer, &type_pointer}, + {7, "+", "ADD_IP", PC_ADDSUB, ASSOC_LEFT, &type_integer, &type_pointer, &type_pointer}, + {7, "-", "SUB_SI", PC_ADDSUB, ASSOC_LEFT, &type_string, &type_integer, &type_string}, + {7, "-", "SUB_PF", PC_ADDSUB, ASSOC_LEFT, &type_pointer, &type_float, &type_pointer}, + {7, "-", "SUB_PI", PC_ADDSUB, ASSOC_LEFT, &type_pointer, &type_integer, &type_pointer}, + {7, "-", "SUB_PP", PC_ADDSUB, ASSOC_LEFT, &type_pointer, &type_pointer, &type_integer}, - {7, "%", "MOD_F", 6, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {7, "%", "MOD_I", 6, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, - {7, "%", "MOD_V", 6, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, + {7, "%", "MOD_F", PC_MULDIV, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {7, "%", "MOD_I", PC_MULDIV, ASSOC_LEFT, &type_integer, &type_integer, &type_integer}, + {7, "%", "MOD_V", PC_MULDIV, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, - {7, "^", "BITXOR_F", 3, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {7, ">>", "RSHIFT_F", 3, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {7, "<<", "LSHIFT_F", 3, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {7, ">>", "RSHIFT_IF", 3, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, - {7, "<<", "LSHIFT_IF", 3, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, - {7, ">>", "RSHIFT_FI", 3, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, - {7, "<<", "LSHIFT_FI", 3, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, + {7, "^", "BITXOR_F", PC_BITXOR, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {7, ">>", "RSHIFT_F", PC_SHIFT, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {7, "<<", "LSHIFT_F", PC_SHIFT, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {7, ">>", "RSHIFT_IF", PC_SHIFT, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, + {7, "<<", "LSHIFT_IF", PC_SHIFT, ASSOC_LEFT, &type_integer, &type_float, &type_integer}, + {7, ">>", "RSHIFT_FI", PC_SHIFT, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, + {7, "<<", "LSHIFT_FI", PC_SHIFT, ASSOC_LEFT, &type_float, &type_integer, &type_integer}, - {7, "&&", "AND_ANY", 7, ASSOC_LEFT, &type_variant, &type_variant, &type_float}, - {7, "||", "OR_ANY", 7, ASSOC_LEFT, &type_variant, &type_variant, &type_float}, + {7, "&&", "AND_ANY", PC_LOGICAND, ASSOC_LEFT, &type_variant, &type_variant, &type_float}, + {7, "||", "OR_ANY", PC_LOGICOR, ASSOC_LEFT, &type_variant, &type_variant, &type_float}, - {7, "+", "ADD_EI", 4, ASSOC_LEFT, &type_entity, &type_integer, &type_entity}, - {7, "+", "ADD_EF", 4, ASSOC_LEFT, &type_entity, &type_float, &type_entity}, - {7, "-", "SUB_EI", 4, ASSOC_LEFT, &type_entity, &type_integer, &type_entity}, - {7, "-", "SUB_EF", 4, ASSOC_LEFT, &type_entity, &type_float, &type_entity}, + {7, "+", "ADD_EI", PC_ADDSUB, ASSOC_LEFT, &type_entity, &type_integer, &type_entity}, + {7, "+", "ADD_EF", PC_ADDSUB, ASSOC_LEFT, &type_entity, &type_float, &type_entity}, + {7, "-", "SUB_EI", PC_ADDSUB, ASSOC_LEFT, &type_entity, &type_integer, &type_entity}, + {7, "-", "SUB_EF", PC_ADDSUB, ASSOC_LEFT, &type_entity, &type_float, &type_entity}, - {7, "&", "BITAND_V", 5, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, - {7, "|", "BITOR_V", 5, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, - {7, "~", "BITNOT_V", -1, ASSOC_LEFT, &type_vector, &type_void, &type_vector}, - {7, "^", "BITXOR_V", 3, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, + {7, "&", "BITAND_V", PC_BITAND, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, + {7, "|", "BITOR_V", PC_BITOR, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, + {7, "~", "BITNOT_V", PC_UNARY, ASSOC_LEFT, &type_vector, &type_void, &type_vector}, + {7, "^", "BITXOR_V", PC_BITXOR, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, - {7, "*^", "POW_F", 3, ASSOC_LEFT, &type_float, &type_float, &type_float}, - {7, "><", "CROSS_V", 3, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, + {7, "*^", "POW_F", PC_MULDIV, ASSOC_LEFT, &type_float, &type_float, &type_float}, + {7, "><", "CROSS_V", PC_MULDIV, ASSOC_LEFT, &type_vector, &type_vector, &type_vector}, - {6, "==", "EQ_FLD", 5, ASSOC_LEFT, &type_field, &type_field, &type_float}, - {6, "!=", "NE_FLD", 5, ASSOC_LEFT, &type_field, &type_field, &type_float}, + {7, "==", "EQ_FLD", PC_EQUALITY, ASSOC_LEFT, &type_field, &type_field, &type_float}, + {7, "!=", "NE_FLD", PC_EQUALITY, ASSOC_LEFT, &type_field, &type_field, &type_float}, {0, NULL} }; @@ -846,22 +880,25 @@ static void OpAssignsTo_Debug(void) */ #undef ASSOC_RIGHT_RESULT +//#define TERM_PRIORITY 0 #define FUNC_PRIORITY 1 #define UNARY_PRIORITY 1 //~ ! -#define NOT_PRIORITY 5 //UNARY_PRIORITY -#define MULDIV_PRIORITY 3 //* / % -#define ADDSUB_PRIORITY 4 //+ - -#define BITSHIFT_PRIORITY 3 //<< >> -#define COMPARISON_PRIORITY 5 //< <= > >= -#define EQUALITY_PRIORITY 5 //== != -#define BITAND_PRIORITY 3 //& -#define BITXOR_PRIORITY 3 //^ -#define BITOR_PRIORITY 3 //| -#define LOGICAND_PRIORITY 7 //&& -#define LOGICOR_PRIORITY 7 //|| -#define TERNARY_PRIORITY 6 //?: -#define ASSIGN_PRIORITY 6 //WRONG compared to C -#define TOP_PRIORITY 7 +//#define MULDIV_PRIORITY priority_class[PC_MULDIV] //* / % +//#define ADDSUB_PRIORITY priority_class[PC_ADDSUB] //+ - +//#define BITSHIFT_PRIORITY priority_class[PC_BITSHIFT] //<< >> +//#define COMPARISON_PRIORITY priority_class[PC_COMPARISON] //< <= > >= +//#define EQUALITY_PRIORITY priority_class[PC_EQUALITY] //== != +//#define BITAND_PRIORITY priority_class[PC_BITAND] //& +//#define BITXOR_PRIORITY priority_class[PC_BITXOR] //^ +//#define BITOR_PRIORITY priority_class[PC_BITOR] //| +//#define LOGICAND_PRIORITY priority_class[PC_LOGICAND] //&& +//#define LOGICOR_PRIORITY priority_class[PC_LOGICOR] //|| +#define TERNARY_PRIORITY priority_class[PC_TERNARY] //?: (in C: (a||b)?(c):(d||e) ) +#define ASSIGN_PRIORITY priority_class[PC_STORE] //QC is WRONG compared to C +//#define COMMA_PRIORITY + +#define TOP_PRIORITY priority_class[MAX_PRIORITY_CLASSES] +#define NOT_PRIORITY priority_class[PC_UNARYNOT] QCC_opcode_t *opcodes_store[] = { @@ -1019,275 +1056,84 @@ QCC_opcode_t *opcodes_none[] = NULL }; -//this system cuts out 10/120 //these evaluate as top first. -QCC_opcode_t *opcodeprioritized[TOP_PRIORITY+1][128] = +QCC_opcode_t *opcodeprioritized[13+1][128]; +int +#ifdef _MSC_VER +__cdecl +#endif +sort_opcodenames(const void*a,const void*b) { - { //don't use -/* &pr_opcodes[OP_DONE], - &pr_opcodes[OP_RETURN], + QCC_opcode_t *opa = *(QCC_opcode_t**)a; + QCC_opcode_t *opb = *(QCC_opcode_t**)b; + if (opa == NULL) + return opb?1:0; + if (opb == NULL) + return -1; + return strcmp(opa->name, opb->name); +} +void QCC_PrioritiseOpcodes(void) +{ + int pcount[MAX_PRIORITY_CLASSES]; + int i, j; + QCC_opcode_t *op; - &pr_opcodes[OP_NOT_F], - &pr_opcodes[OP_NOT_V], - &pr_opcodes[OP_NOT_S], - &pr_opcodes[OP_NOT_ENT], - &pr_opcodes[OP_NOT_FNC], + priority_class[PC_NONE] = 0; + priority_class[PC_UNARY] = 0; + priority_class[PC_MEMBER] = 0; - &pr_opcodes[OP_IF], - &pr_opcodes[OP_IFNOT], - &pr_opcodes[OP_CALL0], - &pr_opcodes[OP_CALL1], - &pr_opcodes[OP_CALL2], - &pr_opcodes[OP_CALL3], - &pr_opcodes[OP_CALL4], - &pr_opcodes[OP_CALL5], - &pr_opcodes[OP_CALL6], - &pr_opcodes[OP_CALL7], - &pr_opcodes[OP_CALL8], - &pr_opcodes[OP_STATE], - &pr_opcodes[OP_GOTO], - - &pr_opcodes[OP_IFNOTS], - &pr_opcodes[OP_IFS], - - &pr_opcodes[OP_NOT_I], -*/ NULL - }, { //1 - -// &pr_opcodes[OP_LOAD_F], -// &pr_opcodes[OP_LOAD_V], -// &pr_opcodes[OP_LOAD_S], -// &pr_opcodes[OP_LOAD_ENT], -// &pr_opcodes[OP_LOAD_FLD], -// &pr_opcodes[OP_LOAD_FNC], -// &pr_opcodes[OP_LOAD_I], -// &pr_opcodes[OP_LOAD_P], -// &pr_opcodes[OP_ADDRESS], - NULL - }, { //2 -/* //conversion. don't use - &pr_opcodes[OP_C_ITOF], - &pr_opcodes[OP_C_FTOI], - &pr_opcodes[OP_CP_ITOF], - &pr_opcodes[OP_CP_FTOI], -*/ NULL - }, { //3 - &pr_opcodes[OP_MUL_F], - &pr_opcodes[OP_MUL_V], - &pr_opcodes[OP_MUL_FV], - &pr_opcodes[OP_MUL_IV], - &pr_opcodes[OP_MUL_VF], - &pr_opcodes[OP_MUL_VI], - &pr_opcodes[OP_MUL_I], - &pr_opcodes[OP_MUL_FI], - &pr_opcodes[OP_MUL_IF], - - &pr_opcodes[OP_DIV_F], - &pr_opcodes[OP_DIV_I], - &pr_opcodes[OP_DIV_FI], - &pr_opcodes[OP_DIV_IF], - &pr_opcodes[OP_DIV_VF], - - &pr_opcodes[OP_BITAND_F], - &pr_opcodes[OP_BITAND_I], - &pr_opcodes[OP_BITAND_IF], - &pr_opcodes[OP_BITAND_FI], - &pr_opcodes[OP_BITAND_V], - - &pr_opcodes[OP_BITOR_F], - &pr_opcodes[OP_BITOR_I], - &pr_opcodes[OP_BITOR_IF], - &pr_opcodes[OP_BITOR_FI], - &pr_opcodes[OP_BITOR_V], - - &pr_opcodes[OP_BITXOR_I], - &pr_opcodes[OP_BITXOR_F], - &pr_opcodes[OP_BITXOR_V], - - &pr_opcodes[OP_RSHIFT_I], - &pr_opcodes[OP_RSHIFT_F], - &pr_opcodes[OP_RSHIFT_IF], - &pr_opcodes[OP_RSHIFT_FI], - - &pr_opcodes[OP_LSHIFT_I], - &pr_opcodes[OP_LSHIFT_F], - &pr_opcodes[OP_LSHIFT_IF], - &pr_opcodes[OP_LSHIFT_FI], - - &pr_opcodes[OP_MOD_F], - &pr_opcodes[OP_MOD_I], - &pr_opcodes[OP_MOD_V], - - &pr_opcodes[OP_POW_F], - &pr_opcodes[OP_CROSS_V], - - NULL - }, { //4 - - &pr_opcodes[OP_ADD_F], - &pr_opcodes[OP_ADD_V], - &pr_opcodes[OP_ADD_I], - &pr_opcodes[OP_ADD_FI], - &pr_opcodes[OP_ADD_IF], - &pr_opcodes[OP_ADD_SF], - &pr_opcodes[OP_ADD_PF], - &pr_opcodes[OP_ADD_FP], - &pr_opcodes[OP_ADD_PI], - &pr_opcodes[OP_ADD_IP], - &pr_opcodes[OP_ADD_EI], - &pr_opcodes[OP_ADD_EF], - - &pr_opcodes[OP_SUB_F], - &pr_opcodes[OP_SUB_V], - &pr_opcodes[OP_SUB_I], - &pr_opcodes[OP_SUB_FI], - &pr_opcodes[OP_SUB_IF], - &pr_opcodes[OP_SUB_S], - &pr_opcodes[OP_SUB_PF], - &pr_opcodes[OP_SUB_PI], - &pr_opcodes[OP_SUB_PP], - &pr_opcodes[OP_SUB_EI], - &pr_opcodes[OP_SUB_EF], - NULL - }, { //5 - - &pr_opcodes[OP_EQ_F], - &pr_opcodes[OP_EQ_V], - &pr_opcodes[OP_EQ_S], - &pr_opcodes[OP_EQ_E], - &pr_opcodes[OP_EQ_FNC], - &pr_opcodes[OP_EQ_I], - &pr_opcodes[OP_EQ_IF], - &pr_opcodes[OP_EQ_FI], - &pr_opcodes[OP_EQ_FLD], - &pr_opcodes[OP_EQ_P], - - &pr_opcodes[OP_NE_F], - &pr_opcodes[OP_NE_V], - &pr_opcodes[OP_NE_S], - &pr_opcodes[OP_NE_E], - &pr_opcodes[OP_NE_FNC], - &pr_opcodes[OP_NE_I], - &pr_opcodes[OP_NE_IF], - &pr_opcodes[OP_NE_FI], - &pr_opcodes[OP_NE_FLD], - &pr_opcodes[OP_NE_P], - - &pr_opcodes[OP_LE_F], - &pr_opcodes[OP_LE_I], - &pr_opcodes[OP_LE_IF], - &pr_opcodes[OP_LE_FI], - &pr_opcodes[OP_LE_P], - &pr_opcodes[OP_GE_F], - &pr_opcodes[OP_GE_I], - &pr_opcodes[OP_GE_IF], - &pr_opcodes[OP_GE_FI], - &pr_opcodes[OP_GE_P], - &pr_opcodes[OP_LT_F], - &pr_opcodes[OP_LT_I], - &pr_opcodes[OP_LT_IF], - &pr_opcodes[OP_LT_FI], - &pr_opcodes[OP_LT_P], - &pr_opcodes[OP_GT_F], - &pr_opcodes[OP_GT_I], - &pr_opcodes[OP_GT_IF], - &pr_opcodes[OP_GT_FI], - &pr_opcodes[OP_GT_P], - - NULL - }, { //6 - &pr_opcodes[OP_STOREP_P], - - &pr_opcodes[OP_STORE_F], - &pr_opcodes[OP_STORE_V], - &pr_opcodes[OP_STORE_S], - &pr_opcodes[OP_STORE_ENT], - &pr_opcodes[OP_STORE_FLD], - &pr_opcodes[OP_STORE_FNC], - &pr_opcodes[OP_STORE_I], - &pr_opcodes[OP_STORE_IF], - &pr_opcodes[OP_STORE_FI], - &pr_opcodes[OP_STORE_P], - - &pr_opcodes[OP_STOREP_F], - &pr_opcodes[OP_STOREP_V], - &pr_opcodes[OP_STOREP_S], - &pr_opcodes[OP_STOREP_ENT], - &pr_opcodes[OP_STOREP_FLD], - &pr_opcodes[OP_STOREP_FNC], - &pr_opcodes[OP_STOREP_I], - &pr_opcodes[OP_STOREP_IF], - &pr_opcodes[OP_STOREP_FI], - - &pr_opcodes[OP_DIVSTORE_F], - &pr_opcodes[OP_DIVSTORE_I], - &pr_opcodes[OP_DIVSTORE_FI], - &pr_opcodes[OP_DIVSTORE_IF], - &pr_opcodes[OP_DIVSTOREP_F], - &pr_opcodes[OP_DIVSTOREP_I], - &pr_opcodes[OP_DIVSTOREP_IF], - &pr_opcodes[OP_DIVSTOREP_FI], - &pr_opcodes[OP_MULSTORE_F], - &pr_opcodes[OP_MULSTORE_VF], - &pr_opcodes[OP_MULSTORE_VI], - &pr_opcodes[OP_MULSTORE_I], - &pr_opcodes[OP_MULSTORE_IF], - &pr_opcodes[OP_MULSTORE_FI], - &pr_opcodes[OP_MULSTOREP_F], - &pr_opcodes[OP_MULSTOREP_VF], - &pr_opcodes[OP_MULSTOREP_VI], - &pr_opcodes[OP_MULSTOREP_I], - &pr_opcodes[OP_MULSTOREP_IF], - &pr_opcodes[OP_MULSTOREP_FI], - &pr_opcodes[OP_ADDSTORE_F], - &pr_opcodes[OP_ADDSTORE_V], - &pr_opcodes[OP_ADDSTORE_I], - &pr_opcodes[OP_ADDSTORE_IF], - &pr_opcodes[OP_ADDSTORE_FI], - &pr_opcodes[OP_ADDSTOREP_F], - &pr_opcodes[OP_ADDSTOREP_V], - &pr_opcodes[OP_ADDSTOREP_I], - &pr_opcodes[OP_ADDSTOREP_IF], - &pr_opcodes[OP_ADDSTOREP_FI], - &pr_opcodes[OP_SUBSTORE_F], - &pr_opcodes[OP_SUBSTORE_V], - &pr_opcodes[OP_SUBSTORE_I], - &pr_opcodes[OP_SUBSTORE_IF], - &pr_opcodes[OP_SUBSTORE_FI], - &pr_opcodes[OP_SUBSTOREP_F], - &pr_opcodes[OP_SUBSTOREP_V], - &pr_opcodes[OP_SUBSTOREP_I], - &pr_opcodes[OP_SUBSTOREP_IF], - &pr_opcodes[OP_SUBSTOREP_FI], - - &pr_opcodes[OP_ANDSTORE_F], - - &pr_opcodes[OP_BITSETSTORE_F], - &pr_opcodes[OP_BITSETSTORE_I], -// &pr_opcodes[OP_BITSETSTORE_IF], -// &pr_opcodes[OP_BITSETSTORE_FI], - &pr_opcodes[OP_BITSETSTOREP_F], - &pr_opcodes[OP_BITSETSTOREP_I], -// &pr_opcodes[OP_BITSETSTOREP_IF], -// &pr_opcodes[OP_BITSETSTOREP_FI], - &pr_opcodes[OP_BITCLRSTORE_F], - &pr_opcodes[OP_BITCLRSTOREP_F], - - NULL - }, { //7 - &pr_opcodes[OP_AND_F], - &pr_opcodes[OP_AND_I], - &pr_opcodes[OP_AND_IF], - &pr_opcodes[OP_AND_FI], - &pr_opcodes[OP_AND_ANY], - &pr_opcodes[OP_OR_F], - &pr_opcodes[OP_OR_I], - &pr_opcodes[OP_OR_IF], - &pr_opcodes[OP_OR_FI], - &pr_opcodes[OP_OR_ANY], - NULL + if (flag_cpriority) + { + priority_class[PC_UNARYNOT] = 1; + priority_class[PC_MULDIV] = 2; + priority_class[PC_ADDSUB] = 3; + priority_class[PC_SHIFT] = 4; + priority_class[PC_RELATION] = 5; + priority_class[PC_EQUALITY] = 6; + priority_class[PC_BITAND] = 7; + priority_class[PC_BITXOR] = 8; + priority_class[PC_BITOR] = 9; + priority_class[PC_LOGICAND] = 10; + priority_class[PC_LOGICOR] = 11; + priority_class[PC_TERNARY] = 12; + priority_class[PC_STORE] = 13; } -}; + else + { + priority_class[PC_UNARYNOT] = 5; + priority_class[PC_MULDIV] = 3; + priority_class[PC_ADDSUB] = 4; + priority_class[PC_SHIFT] = 3; + priority_class[PC_RELATION] = 5; + priority_class[PC_EQUALITY] = 5; + priority_class[PC_BITAND] = 3; + priority_class[PC_BITXOR] = 3; + priority_class[PC_BITOR] = 3; + priority_class[PC_LOGICAND] = 7; + priority_class[PC_LOGICOR] = 7; + priority_class[PC_TERNARY] = 6; + priority_class[PC_STORE] = 6; + } + priority_class[MAX_PRIORITY_CLASSES] = 0; + for (j = 0; j < MAX_PRIORITY_CLASSES; j++) + if (priority_class[MAX_PRIORITY_CLASSES] < priority_class[j]) + priority_class[MAX_PRIORITY_CLASSES] = priority_class[j]; + + memset(pcount, 0, sizeof(pcount)); + memset(opcodeprioritized, 0, sizeof(opcodeprioritized)); + for (i = 0; pr_opcodes[i].name; i++) + { + op = &pr_opcodes[i]; + j = priority_class[op->priorityclass]; + if (j <= 0 || j > priority_class[MAX_PRIORITY_CLASSES]) + continue; //class doesn't need prioritising + opcodeprioritized[j][pcount[j]++] = op; + } + + //operators need to be sorted so we don't have to scan through all of them. should probably have some better table for that. + for (j = 0; j <= TOP_PRIORITY; j++) + qsort (&opcodeprioritized[j][0], pcount[j], sizeof(opcodeprioritized[j][0]), sort_opcodenames); +} pbool QCC_OPCodeValid(QCC_opcode_t *op) { @@ -1639,6 +1485,9 @@ static int QCC_ShouldConvert(QCC_type_t *from, etype_t wanted) if (from->type == ev_integer && wanted == ev_float) return OP_CONV_ITOF; + + if (from->type == ev_float && wanted == ev_vector) + return OP_MUL_FV; } /*impossible*/ @@ -1647,6 +1496,7 @@ static int QCC_ShouldConvert(QCC_type_t *from, etype_t wanted) QCC_sref_t QCC_SupplyConversionForAssignment(QCC_ref_t *to, QCC_sref_t from, QCC_type_t *wanted, pbool fatal) { int o; + QCC_sref_t rhs; if (wanted->type == ev_accessor && wanted->parentclass && from.cast->type != ev_accessor) wanted = wanted->parentclass; @@ -1682,12 +1532,17 @@ QCC_sref_t QCC_SupplyConversionForAssignment(QCC_ref_t *to, QCC_sref_t from, QCC return from; } - return QCC_PR_Statement(&pr_opcodes[o], from, nullsref, NULL); //conversion return value + if (o == OP_MUL_FV) + rhs = QCC_MakeVectorConst(1,1,1); + else + rhs = nullsref; + return QCC_PR_Statement(&pr_opcodes[o], from, rhs, NULL); //conversion return value } QCC_sref_t QCC_SupplyConversion(QCC_sref_t var, etype_t wanted, pbool fatal) { extern char *basictypenames[]; int o; + QCC_sref_t rhs; o = QCC_ShouldConvert(var.cast, wanted); @@ -1710,14 +1565,12 @@ QCC_sref_t QCC_SupplyConversion(QCC_sref_t var, etype_t wanted, pbool fatal) return var; } - return QCC_PR_Statement(&pr_opcodes[o], var, nullsref, NULL); //conversion return value + if (o == OP_MUL_FV) + rhs = QCC_MakeVectorConst(1,1,1); + else + rhs = nullsref; + return QCC_PR_Statement(&pr_opcodes[o], var, rhs, NULL); //conversion return value } -QCC_sref_t QCC_MakeTranslateStringConst(char *value); -QCC_sref_t QCC_MakeStringConst(char *value); -QCC_sref_t QCC_MakeStringConstLength(char *value, int length); -QCC_sref_t QCC_MakeFloatConst(float value); -QCC_sref_t QCC_MakeIntConst(int value); -QCC_sref_t QCC_MakeVectorConst(float a, float b, float c); size_t tempslocked; //stats size_t tempsused; @@ -3636,11 +3489,13 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ op = &pr_opcodes[OP_SUB_I]; var_b = var_a; var_a = QCC_MakeIntConst(~0); + var_a.sym->referenced = true; break; case OP_BITNOT_F: op = &pr_opcodes[OP_SUB_F]; var_b = var_a; var_a = QCC_MakeFloatConst(-1); //divVerent says -1 is safe, even with floats. I guess I'm just too paranoid. + var_a.sym->referenced = true; break; case OP_BITNOT_V: op = &pr_opcodes[OP_SUB_V]; @@ -4011,11 +3866,26 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ else { QCC_sref_t fnc = QCC_PR_GetSRef(NULL, "bitshift", NULL, false, 0, 0); - if (!fnc.cast) - QCC_PR_ParseError(0, "bitshift function not defined: cannot emulate OP_LSHIFT_F*"); - var_c = QCC_PR_GenerateFunctionCall2(nullsref, fnc, var_a, type_float, var_b, type_float); - var_c.cast = *op->type_c; - return var_c; + if (fnc.cast) + { + var_c = QCC_PR_GenerateFunctionCall2(nullsref, fnc, var_a, type_float, var_b, type_float); + var_c.cast = *op->type_c; + return var_c; + } + fnc = QCC_PR_GetSRef(NULL, "pow", NULL, false, 0, 0); + if (fnc.cast) + { //a<type_c; + return var_c; + } + fnc = QCC_PR_GetSRef(NULL, "pow", NULL, false, 0, 0); + if (fnc.cast) + { //a<s_line; - pr_scope = QCC_PR_GenerateQCFunction(scope, scope->type, 0); + pr_scope = QCC_PR_GenerateQCFunction(scope, scope->type, NULL); //reset the locals chain pr.local_head.nextlocal = NULL; pr.local_tail = &pr.local_head; @@ -7741,6 +7634,18 @@ QCC_sref_t QCC_TryEvaluateCast(QCC_sref_t src, QCC_type_t *cast, pbool implicit) /*cast from float->int will convert*/ else if ((totype == ev_integer || (totype == ev_entity && !implicit)) && src.cast->type == ev_float) src = QCC_PR_Statement (&pr_opcodes[OP_CONV_FTOI], src, nullsref, NULL); + else if (totype == ev_vector && src.cast->type == ev_float) + { + if (implicit) + { + char typea[256]; + char typeb[256]; + TypeName(src.cast, typea, sizeof(typea)); + TypeName(cast, typeb, sizeof(typeb)); + QCC_PR_ParseWarning(WARN_IMPLICITVARIANTCAST, "Implicit cast from %s to %s", typea, typeb); + } + src = QCC_PR_Statement (&pr_opcodes[OP_MUL_FV], src, QCC_MakeVectorConst(1,1,1), NULL); + } else if (totype == ev_entity && src.cast->type == ev_entity) { if (implicit) @@ -7935,9 +7840,9 @@ QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags) if (t == ev_float) e2 = QCC_PR_Statement (&pr_opcodes[OP_BITNOT_F], e, nullsref, NULL); else if (t == ev_integer) - e2 = QCC_PR_Statement (&pr_opcodes[OP_BITNOT_I], e, nullsref, NULL); //functions are integer values too. + e2 = QCC_PR_Statement (&pr_opcodes[OP_BITNOT_I], e, nullsref, NULL); else if (t == ev_vector) - e2 = QCC_PR_Statement (&pr_opcodes[OP_BITNOT_V], e, nullsref, NULL); //functions are integer values too. + e2 = QCC_PR_Statement (&pr_opcodes[OP_BITNOT_V], e, nullsref, NULL); else { e2 = nullsref; // shut up compiler warning; @@ -9342,6 +9247,7 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) QCC_statement_t *fromj, *elsej, *truthstore; QCC_sref_t val = QCC_RefToDef(lhsr, true); const QCC_eval_t *eval = QCC_SRef_EvalConst(val); + pbool lvalisnull = false; if (pr_scope) eval = NULL; //FIXME: we need the gotos to avoid sideeffects, which is annoying. if (QCC_PR_CheckToken(":")) @@ -9364,6 +9270,7 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) eval = NULL; //r=a?:b -> if (a) r=a else r=b; fromj = QCC_Generate_OP_IFNOT(val, true); + lvalisnull = QCC_SRef_IsNull(val); r = QCC_GetTemp(val.cast); QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[(r.cast->size>=3)?OP_STORE_V:OP_STORE_F], val, r, &truthstore, STFL_PRESERVEB)); } @@ -9393,6 +9300,7 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) val = QCC_PR_Expression(TOP_PRIORITY, 0); if (val.cast->type == ev_integer && !QCC_OPCodeValid(&pr_opcodes[OP_STORE_I])) val = QCC_SupplyConversion(val, ev_float, true); + lvalisnull = QCC_SRef_IsNull(val); r = QCC_GetTemp(val.cast); QCC_FreeTemp(QCC_PR_StatementFlags(&pr_opcodes[(r.cast->size>=3)?OP_STORE_V:OP_STORE_F], val, r, &truthstore, STFL_PRESERVEB)); //r can be stomped upon until its reused anyway @@ -9421,10 +9329,10 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) if (typecmp(val.cast, r.cast) != 0) { - if (QCC_SRef_IsNull(val)) - val = QCC_EvaluateCast(val, r.cast, true); - else if (QCC_SRef_IsNull(r)) - r = QCC_EvaluateCast(r, val.cast, true); + if (QCC_SRef_IsNull(val) && r.cast->size == val.cast->size) + val.cast = r.cast; //null is null... unless its a vector... + else if (lvalisnull && r.cast->size == val.cast->size) + r.cast = val.cast; //null is null... unless its a vector... else if (typecmp_lax(val.cast, r.cast) != 0) { char typebuf1[256]; @@ -9462,7 +9370,7 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) QCC_PR_ParseWarning(WARN_UNEXPECTEDPUNCT, "Expected punctuation"); } - if (priority == 6) + if (priority == ASSIGN_PRIORITY) { //assignments QCC_opcode_t **ops = NULL, **ops_ptr; char *opname = NULL; @@ -9540,13 +9448,13 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) QCC_PR_ParseError(ERR_INTERNAL, "Assignment to post-inc result"); if (lhsr->readonly) { - QCC_PR_ParseWarning(WARN_ASSIGNMENTTOCONSTANT, "Assignment to lvalue"); + QCC_PR_ParseWarning(WARN_ASSIGNMENTTOCONSTANT, "Assignment to const"); QCC_PR_ParsePrintSRef(WARN_ASSIGNMENTTOCONSTANT, lhsr->base); if (lhsr->index.cast) QCC_PR_ParsePrintSRef(WARN_ASSIGNMENTTOCONSTANT, lhsr->index); } - rhsr = QCC_PR_RefExpression (&rhsbuf, priority, exprflags | EXPR_DISALLOW_ARRAYASSIGN); + rhsr = QCC_PR_RefExpression (&rhsbuf, priority, exprflags | EXPR_DISALLOW_ARRAYASSIGN|EXPR_DISALLOW_COMMA); if (conditional&1) QCC_PR_ParseWarning(WARN_ASSIGNMENTINCONDITIONAL, "suggest parenthesis for assignment used as truth value ."); @@ -9666,16 +9574,14 @@ QCC_ref_t *QCC_PR_RefExpression (QCC_ref_t *retbuf, int priority, int exprflags) continue; logicjump = NULL; - if (opt_logicops && lhsr->type == REF_GLOBAL) + lhsd = QCC_RefToDef(lhsr, true); + if (opt_logicops && lhsd.cast->size == 1) { - lhsd = QCC_RefToDef(lhsr, true); - if (op == &pr_opcodes[OP_AND_F]) //guarenteed to be false if the lhs is false + if (!strcmp(op->name, "&&")) //guarenteed to be false if the lhs is false logicjump = QCC_Generate_OP_IFNOT(lhsd, true); - else if (op == &pr_opcodes[OP_OR_F]) //guarenteed to be true if the lhs is true + else if (!strcmp(op->name, "||")) //guarenteed to be true if the lhs is true logicjump = QCC_Generate_OP_IF(lhsd, true); } - else - lhsd = QCC_RefToDef(lhsr, true); rhsr = QCC_PR_RefExpression (&rhsbuf, priority-1, exprflags | EXPR_DISALLOW_ARRAYASSIGN); @@ -10007,12 +9913,21 @@ void QCC_PR_ParseStatement_For(void) do { type = QCC_PR_ParseType (false, true); - if (!type) - type = lt; - pr_assumetermtype = lt = type; - pr_assumetermscope = pr_scope; - pr_assumetermflags = 0; - QCC_PR_DiscardExpression(TOP_PRIORITY, EXPR_DISALLOW_COMMA); + if (type) + { + d = QCC_PR_GetDef (type, QCC_PR_ParseName(), pr_scope, true, 0, 0); + if (QCC_PR_CheckToken("=")) + QCC_PR_ParseInitializerDef(d, 0); + QCC_FreeDef(d); + lt = type; + } + else + { + pr_assumetermtype = lt; + pr_assumetermscope = pr_scope; + pr_assumetermflags = 0; + QCC_PR_DiscardExpression(TOP_PRIORITY, EXPR_DISALLOW_COMMA); + } } while(QCC_PR_CheckToken(",")); pr_assumetermtype = NULL; QCC_PR_Expect(";"); @@ -10159,10 +10074,24 @@ void QCC_PR_ParseStatement (void) { PR_GenerateReturnOuts(); if (pr_scope->type->aux_type->type != ev_void) + { QCC_PR_ParseWarning(WARN_MISSINGRETURNVALUE, "\'%s\' returned nothing, expected %s", pr_scope->name, pr_scope->type->aux_type->name); - if (opt_return_only) - QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_DONE], nullsref, nullsref, NULL)); - else + //this should not normally happen + if (!pr_scope->returndef.cast) + { //but if it does, allocate a local that can be return=foo; before the return. depend upon qc's null initialisation rules for the default value. + pr_scope->returndef = QCC_PR_GetSRef(pr_scope->type->aux_type, "ret*", pr_scope, true, 0, GDF_NONE); + QCC_FreeTemp(pr_scope->returndef); + } + } + if (pr_scope->returndef.cast) + { + QCC_ForceUnFreeDef(pr_scope->returndef.sym); + QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_RETURN], pr_scope->returndef, nullsref, NULL)); + return; + } +// if (opt_return_only) +// QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_DONE], nullsref, nullsref, NULL)); +// else QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_RETURN], nullsref, nullsref, NULL)); return; } @@ -10171,7 +10100,7 @@ void QCC_PR_ParseStatement (void) { QCC_ref_t r; if (!pr_scope->returndef.cast) - pr_scope->returndef = QCC_PR_GetSRef(pr_scope->type->aux_type, "return", pr_scope, true, 0, GDF_NONE); + pr_scope->returndef = QCC_PR_GetSRef(pr_scope->type->aux_type, "ret*", pr_scope, true, 0, GDF_NONE); else QCC_ForceUnFreeDef(pr_scope->returndef.sym); @@ -11870,68 +11799,65 @@ void QCC_Marshal_Locals(int firststatement, int laststatement) QCC_def_t *local; pbool error = false; - - - if (!pr.local_head.nextlocal) //nothing to marshal - { - return; - } - - if (1) - { - if (qccwarningaction[WARN_UNINITIALIZED]) - QCC_CheckUninitialised(firststatement, laststatement); //still need to call it for warnings, but if those warnings are off we can skip the cost - } - else if (!pr_scope->def->accumulate && !opt_locals_overlapping) - { - if (qccwarningaction[WARN_UNINITIALIZED]) - QCC_CheckUninitialised(firststatement, laststatement); //still need to call it for warnings, but if those warnings are off we can skip the cost - error = true; //always use the legacy behaviour - } - else if (QCC_CheckUninitialised(firststatement, laststatement) && !pr_scope->def->accumulate) - { - error = true; -// QCC_PR_Note(ERR_INTERNAL, strings+s_file, pr_source_line, "Not overlapping locals from %s due to uninitialised locals", pr_scope->name); - } - else - { - //make sure we're allowed to marshall this function's locals - for (local = pr.local_head.nextlocal; local; local = local->nextlocal) + if (pr.local_head.nextlocal) //only check if there's actually somthing to check + { //FIXME: we should just insert extra statements to clear any we deem uninitialised, instead of generating errors etc. + //then we can overlap all functions always without worrying. + if (flag_allowuninit) { - if (local->isstatic) - continue; //static variables are globals - if (local->constant && local->initialized) - continue; //as are initialised consts, because its pointless otherwise. - - //FIXME: check for uninitialised locals. - //these matter when the function goes recursive (and locals marshalling counts as recursive every time). - if (local->symboldata[0]._int) + if (qccwarningaction[WARN_UNINITIALIZED]) + QCC_CheckUninitialised(firststatement, laststatement); //still need to call it for warnings, but if those warnings are off we can skip the cost + } + else if (!pr_scope->def->accumulate && !opt_locals_overlapping) + { + if (qccwarningaction[WARN_UNINITIALIZED]) + QCC_CheckUninitialised(firststatement, laststatement); //still need to call it for warnings, but if those warnings are off we can skip the cost + error = true; //always use the legacy behaviour + } + else if (QCC_CheckUninitialised(firststatement, laststatement) && !pr_scope->def->accumulate) + { + error = true; + // QCC_PR_Note(ERR_INTERNAL, strings+s_file, pr_source_line, "Not overlapping locals from %s due to uninitialised locals", pr_scope->name); + } + else + { + //make sure we're allowed to marshall this function's locals + for (local = pr.local_head.nextlocal; local; local = local->nextlocal) { - QCC_PR_Note(ERR_INTERNAL, local->filen, local->s_line, "Marshaling non-const initialised %s", local->name); - error = true; - } + if (local->isstatic) + continue; //static variables are actually globals + if (local->constant && local->initialized) + continue; //as are initialised consts, because its pointless otherwise. - if (local->constant) - { - QCC_PR_Note(ERR_INTERNAL, local->filen, local->s_line, "Marshaling const %s", local->name); - error = true; + //FIXME: check for uninitialised locals. + //these matter when the function goes recursive (and locals marshalling counts as recursive every time). + if (local->symboldata[0]._int) + { + QCC_PR_Note(ERR_INTERNAL, local->filen, local->s_line, "Marshaling non-const initialised %s", local->name); + error = true; + } + + /*if (local->constant) + { + QCC_PR_Note(ERR_INTERNAL, local->filen, local->s_line, "Marshaling const %s", local->name); + error = true; + }*/ } } - } - //func(&somelocal) reuses the same memory address for both caller and callee. there's nothing we safely do to fix recursive functions, but we can at least stop -Olo from breaking things more. - if (!error) - { - int i; - QCC_statement_t *st; - for (i = firststatement; i < laststatement; i++) + //func(&somelocal) reuses the same memory address for both caller and callee. there's nothing we safely do to fix recursive functions, but we can at least stop -Olo from breaking things more. + if (!error) { - st = &statements[i]; - - if (st->op == OP_GLOBALADDRESS && st->a.sym->scope) + int i; + QCC_statement_t *st; + for (i = firststatement; i < laststatement; i++) { - error = true; - break; + st = &statements[i]; + + if (st->op == OP_GLOBALADDRESS && st->a.sym->scope) + { + error = true; + break; + } } } } @@ -12129,10 +12055,15 @@ QCC_function_t *QCC_PR_GenerateBuiltinFunction (QCC_def_t *def, int builtinnum, func->def = def; return func; } -QCC_function_t *QCC_PR_GenerateQCFunction (QCC_def_t *def, QCC_type_t *type, unsigned int pif_flags) +static QCC_function_t *QCC_PR_GenerateQCFunction (QCC_def_t *def, QCC_type_t *type, unsigned int *pif_flags) { - QCC_function_t *func; - if ((pif_flags & PIF_ACCUMULATE) && !(pif_flags & PIF_WRAP)) + QCC_function_t *func = NULL; + if (numfunctions >= MAX_FUNCTIONS) + QCC_PR_ParseError(ERR_INTERNAL, "Too many functions - %i\nAdd \"MAX_FUNCTIONS\" \"%i\" to qcc.cfg", numfunctions, (numfunctions+4096)&~4095); + + if (!pif_flags) + ; + else if ((*pif_flags & PIF_ACCUMULATE) && !(*pif_flags & PIF_WRAP)) { if (def->symboldata[0].function) { @@ -12145,15 +12076,24 @@ QCC_function_t *QCC_PR_GenerateQCFunction (QCC_def_t *def, QCC_type_t *type, uns return func; } } - - if (numfunctions >= MAX_FUNCTIONS) - QCC_PR_ParseError(ERR_INTERNAL, "Too many functions - %i\nAdd \"MAX_FUNCTIONS\" \"%i\" to qcc.cfg", numfunctions, (numfunctions+4096)&~4095); - if ((pif_flags&PIF_WRAP) && def->symboldata[0].function) + else if ((*pif_flags&PIF_WRAP) && def->symboldata[0].function) { QCC_def_t *locals; - QCC_function_t *prior = &functions[numfunctions++]; + QCC_function_t *prior; func = &functions[def->symboldata[0].function]; + if ((*pif_flags&PIF_AUTOWRAP) && func->statements && func->def == def && func->type == type && func->parentscope == pr_scope) + { + *pif_flags &= ~(PIF_WRAP|PIF_AUTOWRAP); + return func; //looks like we should be able to just reuse it. no need to wrap. + } + prior = &functions[numfunctions++]; memcpy(prior, func, sizeof(*prior)); + + //FIXME: we need a proper algorithm to generate valid anonymous function names. + prior->name = qccHunkAlloc(6+strlen(func->name)+1); + strcpy(prior->name, "prior*"); + strcpy(prior->name+6, func->name); + memset(func, 0, sizeof(*func)); for (locals = prior->firstlocal; locals; locals = locals->nextlocal) @@ -12163,12 +12103,12 @@ QCC_function_t *QCC_PR_GenerateQCFunction (QCC_def_t *def, QCC_type_t *type, uns locals->scope = prior; } } - else if (pif_flags&PIF_WRAP) + else if (*pif_flags&PIF_WRAP) { QCC_PR_ParseError(ERR_INTERNAL, "cannot wrap bodyless function %s", def->name); return NULL; } - else + if (!func) func = &functions[numfunctions++]; func->filen = s_filen; func->s_filed = s_filed; @@ -12333,7 +12273,7 @@ QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_def_t *def, QCC_type_t *typ // if (type->vargs) // QCC_PR_ParseError (ERR_FUNCTIONWITHVARGS, "QC function with variable arguments and function body"); - f = QCC_PR_GenerateQCFunction(def, type, pif_flags); + f = QCC_PR_GenerateQCFunction(def, type, &pif_flags); QCC_PR_ResumeFunction(f); @@ -12513,11 +12453,17 @@ QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_def_t *def, QCC_type_t *typ //accumulate implies wrap when the first function wasn't defined to accumulate (should really be explicit, but gmqcc compat) if (pif_flags & PIF_AUTOWRAP) { + QCC_def_t *arg; QCC_sref_t args[MAX_PARMS+MAX_EXTRA_PARMS]; QCC_sref_t r; unsigned int i; - for (i = 0; i < type->num_parms; i++) - args[i] = QCC_PR_GetSRef (type->params[i].type, pr_parm_names[i], pr_scope, 2, 0, false); + for (i=0, arg=pr.local_head.nextlocal ; inum_parms; i++, arg = arg->deftail->nextlocal) + { + QCC_ForceUnFreeDef(arg); + args[i].sym = arg; + args[i].ofs = 0; + args[i].cast = type->params[i].type; + } r = QCC_PR_GenerateFunctionCallSref(nullsref, QCC_MakeSRefForce(prior, 0, prior->type), args, type->num_parms); prior->referenced = true; @@ -12526,7 +12472,7 @@ QCC_function_t *QCC_PR_ParseImmediateStatements (QCC_def_t *def, QCC_type_t *typ else { if (!f->returndef.cast) - f->returndef = QCC_PR_GetSRef(f->type->aux_type, "return", pr_scope, true, 0, 0); + f->returndef = QCC_PR_GetSRef(f->type->aux_type, "ret*", pr_scope, true, 0, 0); QCC_StoreToSRef(f->returndef, r, type, false, false); } } @@ -12765,7 +12711,7 @@ QCC_def_t *QCC_PR_EmitArrayGetVector(QCC_sref_t array) if (numfunctions >= MAX_FUNCTIONS) QCC_Error(ERR_INTERNAL, "Too many function defs"); - pr_scope = QCC_PR_GenerateQCFunction(func, ftype, 0); + pr_scope = QCC_PR_GenerateQCFunction(func, ftype, NULL); pr_source_line = pr_token_line_last = pr_scope->line = array.sym->s_line; //thankfully these functions are emitted after compilation. pr_scope->filen = array.sym->filen; pr_scope->s_filed = array.sym->s_filed; @@ -12822,7 +12768,7 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, QCC_def_t *arraydef, char *ar // vectortrick.cast = vectortrick.sym->type; // } - pr_scope = QCC_PR_GenerateQCFunction(scope, scope->type, 0); + pr_scope = QCC_PR_GenerateQCFunction(scope, scope->type, NULL); pr_source_line = pr_token_line_last = pr_scope->line = thearray.sym->s_line; //thankfully these functions are emitted after compilation. pr_scope->filen = thearray.sym->filen; pr_scope->s_filed = thearray.sym->s_filed; @@ -12930,7 +12876,7 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *scope, QCC_def_t *arraydef, char *ar errmsg = QCC_MakeStringConst("bounds check failed\n"); if (!errfnc.cast) { - errfnc = QCC_MakeIntConst(0); + errfnc = QCC_MakeIntConst(~0); errfnc.cast = type_function; } QCC_FreeTemp(QCC_PR_GenerateFunctionCall1(nullsref, errfnc, errmsg, type_string)); @@ -13012,7 +12958,7 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, QCC_def_t *arraydef, char *ar s_filen = arraydef->filen; s_filed = arraydef->s_filed; - pr_scope = QCC_PR_GenerateQCFunction(scope, scope->type, 0); + pr_scope = QCC_PR_GenerateQCFunction(scope, scope->type, NULL); pr_source_line = pr_token_line_last = pr_scope->line = thearray.sym->s_line; //thankfully these functions are emitted after compilation. pr_scope->filen = thearray.sym->filen; pr_scope->s_filed = thearray.sym->s_filed; @@ -13063,7 +13009,7 @@ void QCC_PR_EmitArraySetFunction(QCC_def_t *scope, QCC_def_t *arraydef, char *ar QCC_sref_t errmsg = QCC_MakeStringConst("bounds check failed\n"); if (!errfnc.cast) { - errfnc = QCC_MakeIntConst(0); + errfnc = QCC_MakeIntConst(~0); errfnc.cast = type_function; } QCC_FreeTemp(QCC_PR_GenerateFunctionCall1(nullsref, errfnc, errmsg, type_string)); @@ -13484,10 +13430,12 @@ QCC_def_t *QCC_PR_GetDef (QCC_type_t *type, const char *name, struct QCC_functio QCC_PR_ParseWarning (WARN_COMPATIBILITYHACK, "%s builtin was redefined as %s. ignoring alternative definition",name, TypeName(type, typebuf1, sizeof(typebuf1))); QCC_PR_ParsePrintDef(WARN_COMPATIBILITYHACK, def); } - else if (1)//def->unused) - { //previous def was norefed + else if (def->unused && !def->referenced && allocate && !def->scope) + { //previous def was norefed and still wasn't used yet. + QCC_PR_ParseWarning (WARN_COMPATIBILITYHACK, "Type redeclaration of %s %s replaces existing variable", TypeName(type, typebuf1, sizeof(typebuf1)), name); + QCC_PR_ParsePrintDef(WARN_COMPATIBILITYHACK, def); def = pHash_GetNext(&localstable, name, def); - continue; // in a different function + continue; } else { @@ -14367,6 +14315,7 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal) type = QCC_PR_DuplicateType(type, false); type->name = name; type->typedefed = true; + pHash_Add(&typedeftable, name, type, qccHunkAlloc(sizeof(bucket_t))); } } while(QCC_PR_CheckToken(",")); QCC_PR_Expect(";"); diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 8b6c5b07..6f31e889 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -1046,7 +1046,8 @@ pbool QCC_PR_Precompiler(void) msg[a] = '\0'; strcpy(qcc_token, msg); a=0; - continue; + 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;itype != ev_accessor) + QCC_PR_ParseError(ERR_NOTANAME, "Type %s cannot be redefined as an accessor", accessorname); 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;inum_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 { diff --git a/engine/qclib/qccgui.c b/engine/qclib/qccgui.c index d6240644..c6e2f536 100644 --- a/engine/qclib/qccgui.c +++ b/engine/qclib/qccgui.c @@ -1698,7 +1698,12 @@ void GenericMenu(WPARAM wParam) break; case IDM_ABOUT: - 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); +#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; case IDM_CASCADE: @@ -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, diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index 05b85179..84581cde 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -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} }; @@ -289,8 +296,11 @@ optimisations_t optimisations[] = {NULL} }; -#define defaultkeyword FLAG_HIDDENINGUI|FLAG_ASDEFAULT|FLAG_MIDCOMPILE -#define nondefaultkeyword FLAG_HIDDENINGUI|0|FLAG_MIDCOMPILE +#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,32 +4056,32 @@ 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)) - { - *optimisations[p].enabled = true; - break; - } + char *a = myargv[i]+2; + pbool state = true; + if (!strnicmp(a, "no-", 3)) + { + 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]); + } } - if (!optimisations[p].enabled) - 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; - } - else - { - p = QCC_WarningForName(myargv[i]+2); - if (p >= 0) - qccwarningaction[p] = WA_WARN; + a+=3; + action = WA_IGNORE; } + p = QCC_WarningForName(a); + if (p >= 0) + 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; diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 29a16bd7..2c619add 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -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)); diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 6523c492..319e4bbd 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -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) diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 96fb2e46..c4b9acb4 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -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; diff --git a/engine/shaders/glsl/lpp_depthnorm.glsl b/engine/shaders/glsl/lpp_depthnorm.glsl index e88cdb86..f4e3a899 100644 --- a/engine/shaders/glsl/lpp_depthnorm.glsl +++ b/engine/shaders/glsl/lpp_depthnorm.glsl @@ -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 diff --git a/engine/shaders/glsl/lpp_light.glsl b/engine/shaders/glsl/lpp_light.glsl index 1f2d3660..19a26811 100644 --- a/engine/shaders/glsl/lpp_light.glsl +++ b/engine/shaders/glsl/lpp_light.glsl @@ -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 diff --git a/engine/shaders/glsl/lpp_wall.glsl b/engine/shaders/glsl/lpp_wall.glsl index cadbecf6..705fa5a3 100644 --- a/engine/shaders/glsl/lpp_wall.glsl +++ b/engine/shaders/glsl/lpp_wall.glsl @@ -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 diff --git a/engine/shaders/glsl/rtlight.glsl b/engine/shaders/glsl/rtlight.glsl index f4978de8..bbe08bab 100644 --- a/engine/shaders/glsl/rtlight.glsl +++ b/engine/shaders/glsl/rtlight.glsl @@ -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*/ diff --git a/plugins/jabber/jabberclient.c b/plugins/jabber/jabberclient.c index c4c47ed0..c9cd763d 100644 --- a/plugins/jabber/jabberclient.c +++ b/plugins/jabber/jabberclient.c @@ -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;