diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 962f8f87a..6446ff109 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -263,6 +263,7 @@ set(SRB2_LUA_SOURCES lua_mathlib.c lua_mobjlib.c lua_playerlib.c + lua_polyobjlib.c lua_script.c lua_skinlib.c lua_thinkerlib.c diff --git a/src/Makefile b/src/Makefile index ee0d50625..2fe0b26cd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -606,8 +606,9 @@ ifndef VALGRIND ifndef NOOBJDUMP @echo Dumping debugging info $(OBJDUMP) $(OBJDUMP_OPTS) $(BIN)/$(EXENAME) > $(BIN)/$(DBGNAME).txt +ifdef WINDOWSHELL -$(GZIP) $(GZIP_OPTS) $(BIN)/$(DBGNAME).txt -ifndef WINDOWSHELL +else -$(GZIP) $(GZIP_OPT2) $(BIN)/$(DBGNAME).txt endif endif @@ -627,8 +628,9 @@ endif reobjdump: @echo Redumping debugging info $(OBJDUMP) $(OBJDUMP_OPTS) $(BIN)/$(DBGNAME) > $(BIN)/$(DBGNAME).txt +ifdef WINDOWSHELL -$(GZIP) $(GZIP_OPTS) $(BIN)/$(DBGNAME).txt -ifndef WINDOWSHELL +else -$(GZIP) $(GZIP_OPT2) $(BIN)/$(DBGNAME).txt endif diff --git a/src/blua/Makefile.cfg b/src/blua/Makefile.cfg index 12ea064b4..eae95ba3a 100644 --- a/src/blua/Makefile.cfg +++ b/src/blua/Makefile.cfg @@ -47,5 +47,6 @@ OBJS:=$(OBJS) \ $(OBJDIR)/lua_skinlib.o \ $(OBJDIR)/lua_thinkerlib.o \ $(OBJDIR)/lua_maplib.o \ + $(OBJDIR)/lua_polyobjlib.o \ $(OBJDIR)/lua_blockmaplib.o \ $(OBJDIR)/lua_hudlib.o diff --git a/src/command.c b/src/command.c index 51dec0f5f..f84500785 100644 --- a/src/command.c +++ b/src/command.c @@ -901,6 +901,9 @@ static void COM_Help_f(void) CONS_Printf(" Current value: %s\n", cvar->string); else CONS_Printf(" Current value: %d\n", cvar->value); + + if (cvar->revert.v.string != NULL && strcmp(cvar->revert.v.string, cvar->string) != 0) + CONS_Printf(" Value before netgame: %s\n", cvar->revert.v.string); } else { @@ -1306,6 +1309,7 @@ void CV_RegisterVar(consvar_t *variable) consvar_vars = variable; } variable->string = variable->zstring = NULL; + memset(&variable->revert, 0, sizeof variable->revert); variable->changed = 0; // new variable has not been modified by the user #ifdef PARANOIA @@ -1418,6 +1422,18 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) for (i = MAXVAL+1; var->PossibleValue[i].strvalue; i++) if (v == var->PossibleValue[i].value || !stricmp(var->PossibleValue[i].strvalue, valstr)) { + if (client && execversion_enabled) + { + if (var->revert.allocated) + { + Z_Free(var->revert.v.string); + } + + var->revert.v.const_munge = var->PossibleValue[i].strvalue; + + return; + } + var->value = var->PossibleValue[i].value; var->string = var->PossibleValue[i].strvalue; goto finish; @@ -1478,12 +1494,36 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) // ...or not. goto badinput; found: + if (client && execversion_enabled) + { + if (var->revert.allocated) + { + Z_Free(var->revert.v.string); + } + + var->revert.v.const_munge = var->PossibleValue[i].strvalue; + + return; + } + var->value = var->PossibleValue[i].value; var->string = var->PossibleValue[i].strvalue; goto finish; } } + if (client && execversion_enabled) + { + if (var->revert.allocated) + { + Z_Free(var->revert.v.string); + } + + var->revert.v.string = Z_StrDup(valstr); + + return; + } + // free the old value string Z_Free(var->zstring); @@ -1702,8 +1742,19 @@ static void CV_LoadVars(UINT8 **p, serverloading = true; for (cvar = consvar_vars; cvar; cvar = cvar->next) + { if (cvar->flags & CV_NETVAR) + { + if (client && cvar->revert.v.string == NULL) + { + cvar->revert.v.const_munge = cvar->string; + cvar->revert.allocated = ( cvar->zstring != NULL ); + cvar->zstring = NULL;/* don't free this */ + } + Setvalue(cvar, cvar->defaultvalue, true); + } + } count = READUINT16(*p); while (count--) @@ -1717,6 +1768,26 @@ static void CV_LoadVars(UINT8 **p, serverloading = false; } +void CV_RevertNetVars(void) +{ + consvar_t * cvar; + + for (cvar = consvar_vars; cvar; cvar = cvar->next) + { + if (cvar->revert.v.string != NULL) + { + Setvalue(cvar, cvar->revert.v.string, false); + + if (cvar->revert.allocated) + { + Z_Free(cvar->revert.v.string); + } + + cvar->revert.v.string = NULL; + } + } +} + void CV_LoadNetVars(UINT8 **p) { CV_LoadVars(p, ReadNetVar); @@ -1790,6 +1861,14 @@ static void CV_SetCVar(consvar_t *var, const char *value, boolean stealth) // send the value of the variable UINT8 buf[128]; UINT8 *p = buf; + + // Loading from a config in a netgame? Set revert value. + if (client && execversion_enabled) + { + Setvalue(var, value, true); + return; + } + if (!(server || (addedtogame && IsPlayerAdmin(consoleplayer)))) { CONS_Printf(M_GetText("Only the server or admin can change: %s %s\n"), var->name, var->string); @@ -2323,18 +2402,43 @@ void CV_SaveVariables(FILE *f) { char stringtowrite[MAXTEXTCMD+1]; - // Silly hack for Min/Max vars - if (!strcmp(cvar->string, "MAX") || !strcmp(cvar->string, "MIN")) + const char * string; + + if (cvar->revert.v.string != NULL) { - if (cvar->flags & CV_FLOAT) - sprintf(stringtowrite, "%f", FIXED_TO_FLOAT(cvar->value)); - else - sprintf(stringtowrite, "%d", cvar->value); + string = cvar->revert.v.string; } else - strcpy(stringtowrite, cvar->string); + { + string = cvar->string; + } - fprintf(f, "%s \"%s\"\n", cvar->name, stringtowrite); + // Silly hack for Min/Max vars +#define MINVAL 0 +#define MAXVAL 1 + if ( + cvar->PossibleValue != NULL && + cvar->PossibleValue[0].strvalue && + stricmp(cvar->PossibleValue[0].strvalue, "MIN") == 0 + ){ // bounded cvar + int which = stricmp(string, "MAX") == 0; + + if (which || stricmp(string, "MIN") == 0) + { + INT32 value = cvar->PossibleValue[which].value; + + if (cvar->flags & CV_FLOAT) + sprintf(stringtowrite, "%f", FIXED_TO_FLOAT(value)); + else + sprintf(stringtowrite, "%d", value); + + string = stringtowrite; + } + } +#undef MINVAL +#undef MAXVAL + + fprintf(f, "%s \"%s\"\n", cvar->name, string); } } diff --git a/src/command.h b/src/command.h index ec19b403a..ea5593395 100644 --- a/src/command.h +++ b/src/command.h @@ -140,6 +140,16 @@ typedef struct consvar_s //NULL, NULL, 0, NULL, NULL |, 0, NULL, NULL, 0, 0, NUL const char *string; // value in string char *zstring; // Either NULL or same as string. // If non-NULL, must be Z_Free'd later. + struct + { + char allocated; // whether to Z_Free + union + { + char * string; + const char * const_munge; + } v; + } revert; // value of netvar before joining netgame + UINT16 netid; // used internaly : netid for send end receive // used only with CV_NETVAR char changed; // has variable been changed by the user? 0 = no, 1 = yes @@ -148,7 +158,7 @@ typedef struct consvar_s //NULL, NULL, 0, NULL, NULL |, 0, NULL, NULL, 0, 0, NUL /* name, defaultvalue, flags, PossibleValue, func */ #define CVAR_INIT( ... ) \ -{ __VA_ARGS__, 0, NULL, NULL, 0U, (char)0, NULL } +{ __VA_ARGS__, 0, NULL, NULL, {0}, 0U, (char)0, NULL } #ifdef OLD22DEMOCOMPAT typedef struct old_demo_var old_demo_var_t; @@ -208,6 +218,9 @@ void CV_SaveVars(UINT8 **p, boolean in_demo); #define CV_SaveNetVars(p) CV_SaveVars(p, false) void CV_LoadNetVars(UINT8 **p); +// then revert after leaving a netgame +void CV_RevertNetVars(void); + #define CV_SaveDemoVars(p) CV_SaveVars(p, true) void CV_LoadDemoVars(UINT8 **p); diff --git a/src/d_clisrv.c b/src/d_clisrv.c index c9490410b..b6974b6cd 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -157,7 +157,7 @@ ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; static textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL}; -consvar_t cv_showjoinaddress = CVAR_INIT ("showjoinaddress", "Off", CV_SAVE, CV_OnOff, NULL); +consvar_t cv_showjoinaddress = CVAR_INIT ("showjoinaddress", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0, NULL}}; consvar_t cv_playbackspeed = CVAR_INIT ("playbackspeed", "1", 0, playbackspeed_cons_t, NULL); @@ -2119,7 +2119,7 @@ static void SV_SendSaveGame(INT32 node) #ifdef DUMPCONSISTENCY #define TMPSAVENAME "badmath.sav" -static consvar_t cv_dumpconsistency = CVAR_INIT ("dumpconsistency", "Off", CV_NETVAR, CV_OnOff, NULL); +static consvar_t cv_dumpconsistency = CVAR_INIT ("dumpconsistency", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); static void SV_SavedGame(void) { @@ -3208,6 +3208,7 @@ void CL_Reset(void) doomcom->numslots = 1; SV_StopServer(); SV_ResetServer(); + CV_RevertNetVars(); // make sure we don't leave any fileneeded gunk over from a failed join fileneedednum = 0; @@ -3677,27 +3678,27 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; consvar_t cv_netticbuffer = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL); -consvar_t cv_allownewplayer = CVAR_INIT ("allowjoin", "On", CV_NETVAR, CV_OnOff, NULL); -consvar_t cv_joinnextround = CVAR_INIT ("joinnextround", "Off", CV_NETVAR, CV_OnOff, NULL); /// \todo not done +consvar_t cv_allownewplayer = CVAR_INIT ("allowjoin", "On", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); +consvar_t cv_joinnextround = CVAR_INIT ("joinnextround", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); /// \todo not done static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {32, "MAX"}, {0, NULL}}; -consvar_t cv_maxplayers = CVAR_INIT ("maxplayers", "8", CV_SAVE, maxplayers_cons_t, NULL); +consvar_t cv_maxplayers = CVAR_INIT ("maxplayers", "8", CV_SAVE|CV_NETVAR, maxplayers_cons_t, NULL); static CV_PossibleValue_t joindelay_cons_t[] = {{1, "MIN"}, {3600, "MAX"}, {0, "Off"}, {0, NULL}}; -consvar_t cv_joindelay = CVAR_INIT ("joindelay", "10", CV_SAVE, joindelay_cons_t, NULL); +consvar_t cv_joindelay = CVAR_INIT ("joindelay", "10", CV_SAVE|CV_NETVAR, joindelay_cons_t, NULL); static CV_PossibleValue_t rejointimeout_cons_t[] = {{1, "MIN"}, {60 * FRACUNIT, "MAX"}, {0, "Off"}, {0, NULL}}; -consvar_t cv_rejointimeout = CVAR_INIT ("rejointimeout", "Off", CV_SAVE|CV_FLOAT, rejointimeout_cons_t, NULL); +consvar_t cv_rejointimeout = CVAR_INIT ("rejointimeout", "Off", CV_SAVE|CV_NETVAR|CV_FLOAT, rejointimeout_cons_t, NULL); static CV_PossibleValue_t resynchattempts_cons_t[] = {{1, "MIN"}, {20, "MAX"}, {0, "No"}, {0, NULL}}; -consvar_t cv_resynchattempts = CVAR_INIT ("resynchattempts", "10", CV_SAVE, resynchattempts_cons_t, NULL); -consvar_t cv_blamecfail = CVAR_INIT ("blamecfail", "Off", CV_SAVE, CV_OnOff, NULL); +consvar_t cv_resynchattempts = CVAR_INIT ("resynchattempts", "10", CV_SAVE|CV_NETVAR, resynchattempts_cons_t, NULL); +consvar_t cv_blamecfail = CVAR_INIT ("blamecfail", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); // max file size to send to a player (in kilobytes) static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {51200, "MAX"}, {0, NULL}}; -consvar_t cv_maxsend = CVAR_INIT ("maxsend", "4096", CV_SAVE, maxsend_cons_t, NULL); -consvar_t cv_noticedownload = CVAR_INIT ("noticedownload", "Off", CV_SAVE, CV_OnOff, NULL); +consvar_t cv_maxsend = CVAR_INIT ("maxsend", "4096", CV_SAVE|CV_NETVAR, maxsend_cons_t, NULL); +consvar_t cv_noticedownload = CVAR_INIT ("noticedownload", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); // Speed of file downloading (in packets per tic) static CV_PossibleValue_t downloadspeed_cons_t[] = {{0, "MIN"}, {32, "MAX"}, {0, NULL}}; -consvar_t cv_downloadspeed = CVAR_INIT ("downloadspeed", "16", CV_SAVE, downloadspeed_cons_t, NULL); +consvar_t cv_downloadspeed = CVAR_INIT ("downloadspeed", "16", CV_SAVE|CV_NETVAR, downloadspeed_cons_t, NULL); static void Got_AddPlayer(UINT8 **p, INT32 playernum); diff --git a/src/d_main.c b/src/d_main.c index d1a414018..c4cde87a3 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1589,6 +1589,12 @@ void D_SRB2Main(void) ultimatemode = true; } + if (M_CheckParm("-splitscreen")) + { + autostart = true; + splitscreen = true; + } + // rei/miru: bootmap (Idea: starts the game on a predefined map) if (bootmap && !(M_CheckParm("-warp") && M_IsNextParm())) { diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 6f4bcdb1d..9082a818a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -204,20 +204,20 @@ static consvar_t cv_fishcake = CVAR_INIT ("fishcake", "Off", CV_CALL|CV_NOSHOWHE #endif static consvar_t cv_dummyconsvar = CVAR_INIT ("dummyconsvar", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff, DummyConsvar_OnChange); -consvar_t cv_restrictskinchange = CVAR_INIT ("restrictskinchange", "Yes", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL); -consvar_t cv_allowteamchange = CVAR_INIT ("allowteamchange", "Yes", CV_NETVAR, CV_YesNo, NULL); +consvar_t cv_restrictskinchange = CVAR_INIT ("restrictskinchange", "Yes", CV_SAVE|CV_NETVAR|CV_CHEAT, CV_YesNo, NULL); +consvar_t cv_allowteamchange = CVAR_INIT ("allowteamchange", "Yes", CV_SAVE|CV_NETVAR, CV_YesNo, NULL); -consvar_t cv_startinglives = CVAR_INIT ("startinglives", "3", CV_NETVAR|CV_CHEAT, startingliveslimit_cons_t, NULL); +consvar_t cv_startinglives = CVAR_INIT ("startinglives", "3", CV_SAVE|CV_NETVAR|CV_CHEAT, startingliveslimit_cons_t, NULL); static CV_PossibleValue_t respawntime_cons_t[] = {{1, "MIN"}, {30, "MAX"}, {0, "Off"}, {0, NULL}}; -consvar_t cv_respawntime = CVAR_INIT ("respawndelay", "3", CV_NETVAR|CV_CHEAT, respawntime_cons_t, NULL); +consvar_t cv_respawntime = CVAR_INIT ("respawndelay", "3", CV_SAVE|CV_NETVAR|CV_CHEAT, respawntime_cons_t, NULL); -consvar_t cv_competitionboxes = CVAR_INIT ("competitionboxes", "Mystery", CV_NETVAR|CV_CHEAT, competitionboxes_cons_t, NULL); +consvar_t cv_competitionboxes = CVAR_INIT ("competitionboxes", "Mystery", CV_SAVE|CV_NETVAR|CV_CHEAT, competitionboxes_cons_t, NULL); #ifdef SEENAMES static CV_PossibleValue_t seenames_cons_t[] = {{0, "Off"}, {1, "Colorless"}, {2, "Team"}, {3, "Ally/Foe"}, {0, NULL}}; consvar_t cv_seenames = CVAR_INIT ("seenames", "Ally/Foe", CV_SAVE, seenames_cons_t, 0); -consvar_t cv_allowseenames = CVAR_INIT ("allowseenames", "Yes", CV_NETVAR, CV_YesNo, NULL); +consvar_t cv_allowseenames = CVAR_INIT ("allowseenames", "Yes", CV_SAVE|CV_NETVAR, CV_YesNo, NULL); #endif // names @@ -264,22 +264,22 @@ consvar_t cv_mouse2opt = CVAR_INIT ("mouse2opt", "0", CV_SAVE, NULL, NULL); consvar_t cv_mouse2port = CVAR_INIT ("mouse2port", "COM2", CV_SAVE, mouse2port_cons_t, NULL); #endif -consvar_t cv_matchboxes = CVAR_INIT ("matchboxes", "Normal", CV_NETVAR|CV_CHEAT, matchboxes_cons_t, NULL); -consvar_t cv_specialrings = CVAR_INIT ("specialrings", "On", CV_NETVAR, CV_OnOff, NULL); -consvar_t cv_powerstones = CVAR_INIT ("powerstones", "On", CV_NETVAR, CV_OnOff, NULL); +consvar_t cv_matchboxes = CVAR_INIT ("matchboxes", "Normal", CV_SAVE|CV_NETVAR|CV_CHEAT, matchboxes_cons_t, NULL); +consvar_t cv_specialrings = CVAR_INIT ("specialrings", "On", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); +consvar_t cv_powerstones = CVAR_INIT ("powerstones", "On", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); -consvar_t cv_recycler = CVAR_INIT ("tv_recycler", "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); -consvar_t cv_teleporters = CVAR_INIT ("tv_teleporter", "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); -consvar_t cv_superring = CVAR_INIT ("tv_superring", "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); -consvar_t cv_supersneakers = CVAR_INIT ("tv_supersneaker", "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); -consvar_t cv_invincibility = CVAR_INIT ("tv_invincibility", "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); -consvar_t cv_jumpshield = CVAR_INIT ("tv_jumpshield", "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); -consvar_t cv_watershield = CVAR_INIT ("tv_watershield", "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); -consvar_t cv_ringshield = CVAR_INIT ("tv_ringshield", "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); -consvar_t cv_forceshield = CVAR_INIT ("tv_forceshield", "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); -consvar_t cv_bombshield = CVAR_INIT ("tv_bombshield", "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); -consvar_t cv_1up = CVAR_INIT ("tv_1up", "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); -consvar_t cv_eggmanbox = CVAR_INIT ("tv_eggman", "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); +consvar_t cv_recycler = CVAR_INIT ("tv_recycler", "5", CV_SAVE|CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); +consvar_t cv_teleporters = CVAR_INIT ("tv_teleporter", "5", CV_SAVE|CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); +consvar_t cv_superring = CVAR_INIT ("tv_superring", "5", CV_SAVE|CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); +consvar_t cv_supersneakers = CVAR_INIT ("tv_supersneaker", "5", CV_SAVE|CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); +consvar_t cv_invincibility = CVAR_INIT ("tv_invincibility", "5", CV_SAVE|CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); +consvar_t cv_jumpshield = CVAR_INIT ("tv_jumpshield", "5", CV_SAVE|CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); +consvar_t cv_watershield = CVAR_INIT ("tv_watershield", "5", CV_SAVE|CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); +consvar_t cv_ringshield = CVAR_INIT ("tv_ringshield", "5", CV_SAVE|CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); +consvar_t cv_forceshield = CVAR_INIT ("tv_forceshield", "5", CV_SAVE|CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); +consvar_t cv_bombshield = CVAR_INIT ("tv_bombshield", "5", CV_SAVE|CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); +consvar_t cv_1up = CVAR_INIT ("tv_1up", "5", CV_SAVE|CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); +consvar_t cv_eggmanbox = CVAR_INIT ("tv_eggman", "5", CV_SAVE|CV_NETVAR|CV_CHEAT, chances_cons_t, NULL); consvar_t cv_ringslinger = CVAR_INIT ("ringslinger", "No", CV_NETVAR|CV_NOSHOWHELP|CV_CALL|CV_CHEAT, CV_YesNo, Ringslinger_OnChange); consvar_t cv_gravity = CVAR_INIT ("gravity", "0.5", CV_RESTRICT|CV_FLOAT|CV_CALL, NULL, Gravity_OnChange); @@ -287,20 +287,20 @@ consvar_t cv_gravity = CVAR_INIT ("gravity", "0.5", CV_RESTRICT|CV_FLOAT|CV_CALL consvar_t cv_soundtest = CVAR_INIT ("soundtest", "0", CV_CALL, NULL, SoundTest_OnChange); static CV_PossibleValue_t minitimelimit_cons_t[] = {{15, "MIN"}, {9999, "MAX"}, {0, NULL}}; -consvar_t cv_countdowntime = CVAR_INIT ("countdowntime", "60", CV_NETVAR|CV_CHEAT, minitimelimit_cons_t, NULL); +consvar_t cv_countdowntime = CVAR_INIT ("countdowntime", "60", CV_SAVE|CV_NETVAR|CV_CHEAT, minitimelimit_cons_t, NULL); -consvar_t cv_touchtag = CVAR_INIT ("touchtag", "Off", CV_NETVAR, CV_OnOff, NULL); -consvar_t cv_hidetime = CVAR_INIT ("hidetime", "30", CV_NETVAR|CV_CALL, minitimelimit_cons_t, Hidetime_OnChange); +consvar_t cv_touchtag = CVAR_INIT ("touchtag", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); +consvar_t cv_hidetime = CVAR_INIT ("hidetime", "30", CV_SAVE|CV_NETVAR|CV_CALL, minitimelimit_cons_t, Hidetime_OnChange); -consvar_t cv_autobalance = CVAR_INIT ("autobalance", "Off", CV_NETVAR|CV_CALL, CV_OnOff, AutoBalance_OnChange); -consvar_t cv_teamscramble = CVAR_INIT ("teamscramble", "Off", CV_NETVAR|CV_CALL|CV_NOINIT, teamscramble_cons_t, TeamScramble_OnChange); -consvar_t cv_scrambleonchange = CVAR_INIT ("scrambleonchange", "Off", CV_NETVAR, teamscramble_cons_t, NULL); +consvar_t cv_autobalance = CVAR_INIT ("autobalance", "Off", CV_SAVE|CV_NETVAR|CV_CALL, CV_OnOff, AutoBalance_OnChange); +consvar_t cv_teamscramble = CVAR_INIT ("teamscramble", "Off", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, teamscramble_cons_t, TeamScramble_OnChange); +consvar_t cv_scrambleonchange = CVAR_INIT ("scrambleonchange", "Off", CV_SAVE|CV_NETVAR, teamscramble_cons_t, NULL); -consvar_t cv_friendlyfire = CVAR_INIT ("friendlyfire", "Off", CV_NETVAR, CV_OnOff, NULL); +consvar_t cv_friendlyfire = CVAR_INIT ("friendlyfire", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); consvar_t cv_itemfinder = CVAR_INIT ("itemfinder", "Off", CV_CALL, CV_OnOff, ItemFinder_OnChange); // Scoring type options -consvar_t cv_overtime = CVAR_INIT ("overtime", "Yes", CV_NETVAR, CV_YesNo, NULL); +consvar_t cv_overtime = CVAR_INIT ("overtime", "Yes", CV_SAVE|CV_NETVAR, CV_YesNo, NULL); consvar_t cv_rollingdemos = CVAR_INIT ("rollingdemos", "On", CV_SAVE, CV_OnOff, NULL); @@ -311,13 +311,13 @@ static CV_PossibleValue_t powerupdisplay_cons_t[] = {{0, "Never"}, {1, "First-pe consvar_t cv_powerupdisplay = CVAR_INIT ("powerupdisplay", "First-person only", CV_SAVE, powerupdisplay_cons_t, NULL); static CV_PossibleValue_t pointlimit_cons_t[] = {{1, "MIN"}, {MAXSCORE, "MAX"}, {0, "None"}, {0, NULL}}; -consvar_t cv_pointlimit = CVAR_INIT ("pointlimit", "None", CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t, PointLimit_OnChange); +consvar_t cv_pointlimit = CVAR_INIT ("pointlimit", "None", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t, PointLimit_OnChange); static CV_PossibleValue_t timelimit_cons_t[] = {{1, "MIN"}, {30, "MAX"}, {0, "None"}, {0, NULL}}; -consvar_t cv_timelimit = CVAR_INIT ("timelimit", "None", CV_NETVAR|CV_CALL|CV_NOINIT, timelimit_cons_t, TimeLimit_OnChange); +consvar_t cv_timelimit = CVAR_INIT ("timelimit", "None", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, timelimit_cons_t, TimeLimit_OnChange); static CV_PossibleValue_t numlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, NULL}}; consvar_t cv_numlaps = CVAR_INIT ("numlaps", "4", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_cons_t, NumLaps_OnChange); static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, "Map default"}, {0, NULL}}; -consvar_t cv_basenumlaps = CVAR_INIT ("basenumlaps", "Map default", CV_NETVAR|CV_CALL|CV_CHEAT, basenumlaps_cons_t, BaseNumLaps_OnChange); +consvar_t cv_basenumlaps = CVAR_INIT ("basenumlaps", "Map default", CV_SAVE|CV_NETVAR|CV_CALL|CV_CHEAT, basenumlaps_cons_t, BaseNumLaps_OnChange); // Point and time limits for every gametype INT32 pointlimits[NUMGAMETYPES]; @@ -328,7 +328,7 @@ consvar_t cv_hazardlog = CVAR_INIT ("hazardlog", "Yes", 0, CV_YesNo, NULL); consvar_t cv_forceskin = CVAR_INIT ("forceskin", "None", CV_NETVAR|CV_CALL|CV_CHEAT, NULL, ForceSkin_OnChange); consvar_t cv_downloading = CVAR_INIT ("downloading", "On", 0, CV_OnOff, NULL); -consvar_t cv_allowexitlevel = CVAR_INIT ("allowexitlevel", "No", CV_NETVAR, CV_YesNo, NULL); +consvar_t cv_allowexitlevel = CVAR_INIT ("allowexitlevel", "No", CV_SAVE|CV_NETVAR, CV_YesNo, NULL); consvar_t cv_killingdead = CVAR_INIT ("killingdead", "Off", CV_NETVAR, CV_OnOff, NULL); @@ -336,11 +336,11 @@ consvar_t cv_netstat = CVAR_INIT ("netstat", "Off", 0, CV_OnOff, NULL); // show static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}}; consvar_t cv_nettimeout = CVAR_INIT ("nettimeout", "350", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange); static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}}; -consvar_t cv_jointimeout = CVAR_INIT ("jointimeout", "350", CV_CALL|CV_SAVE, jointimeout_cons_t, JoinTimeout_OnChange); -consvar_t cv_maxping = CVAR_INIT ("maxping", "0", CV_SAVE, CV_Unsigned, NULL); +consvar_t cv_jointimeout = CVAR_INIT ("jointimeout", "350", CV_CALL|CV_SAVE|CV_NETVAR, jointimeout_cons_t, JoinTimeout_OnChange); +consvar_t cv_maxping = CVAR_INIT ("maxping", "0", CV_SAVE|CV_NETVAR, CV_Unsigned, NULL); static CV_PossibleValue_t pingtimeout_cons_t[] = {{8, "MIN"}, {120, "MAX"}, {0, NULL}}; -consvar_t cv_pingtimeout = CVAR_INIT ("pingtimeout", "10", CV_SAVE, pingtimeout_cons_t, NULL); +consvar_t cv_pingtimeout = CVAR_INIT ("pingtimeout", "10", CV_SAVE|CV_NETVAR, pingtimeout_cons_t, NULL); // show your ping on the HUD next to framerate. Defaults to warning only (shows up if your ping is > maxping) static CV_PossibleValue_t showping_cons_t[] = {{0, "Off"}, {1, "Always"}, {2, "Warning"}, {0, NULL}}; @@ -348,25 +348,25 @@ consvar_t cv_showping = CVAR_INIT ("showping", "Warning", CV_SAVE, showping_cons // Intermission time Tails 04-19-2002 static CV_PossibleValue_t inttime_cons_t[] = {{0, "MIN"}, {3600, "MAX"}, {0, NULL}}; -consvar_t cv_inttime = CVAR_INIT ("inttime", "10", CV_NETVAR, inttime_cons_t, NULL); +consvar_t cv_inttime = CVAR_INIT ("inttime", "10", CV_SAVE|CV_NETVAR, inttime_cons_t, NULL); static CV_PossibleValue_t coopstarposts_cons_t[] = {{0, "Per-player"}, {1, "Shared"}, {2, "Teamwork"}, {0, NULL}}; -consvar_t cv_coopstarposts = CVAR_INIT ("coopstarposts", "Per-player", CV_NETVAR|CV_CALL, coopstarposts_cons_t, CoopStarposts_OnChange); +consvar_t cv_coopstarposts = CVAR_INIT ("coopstarposts", "Per-player", CV_SAVE|CV_NETVAR|CV_CALL, coopstarposts_cons_t, CoopStarposts_OnChange); static CV_PossibleValue_t cooplives_cons_t[] = {{0, "Infinite"}, {1, "Per-player"}, {2, "Avoid Game Over"}, {3, "Single pool"}, {0, NULL}}; -consvar_t cv_cooplives = CVAR_INIT ("cooplives", "Avoid Game Over", CV_NETVAR|CV_CALL|CV_CHEAT, cooplives_cons_t, CoopLives_OnChange); +consvar_t cv_cooplives = CVAR_INIT ("cooplives", "Avoid Game Over", CV_SAVE|CV_NETVAR|CV_CALL|CV_CHEAT, cooplives_cons_t, CoopLives_OnChange); static CV_PossibleValue_t advancemap_cons_t[] = {{0, "Off"}, {1, "Next"}, {2, "Random"}, {0, NULL}}; -consvar_t cv_advancemap = CVAR_INIT ("advancemap", "Next", CV_NETVAR, advancemap_cons_t, NULL); +consvar_t cv_advancemap = CVAR_INIT ("advancemap", "Next", CV_SAVE|CV_NETVAR, advancemap_cons_t, NULL); static CV_PossibleValue_t playersforexit_cons_t[] = {{0, "One"}, {1, "1/4"}, {2, "Half"}, {3, "3/4"}, {4, "All"}, {0, NULL}}; -consvar_t cv_playersforexit = CVAR_INIT ("playersforexit", "All", CV_NETVAR, playersforexit_cons_t, NULL); +consvar_t cv_playersforexit = CVAR_INIT ("playersforexit", "All", CV_SAVE|CV_NETVAR, playersforexit_cons_t, NULL); -consvar_t cv_exitmove = CVAR_INIT ("exitmove", "On", CV_NETVAR|CV_CALL, CV_OnOff, ExitMove_OnChange); +consvar_t cv_exitmove = CVAR_INIT ("exitmove", "On", CV_SAVE|CV_NETVAR|CV_CALL, CV_OnOff, ExitMove_OnChange); consvar_t cv_runscripts = CVAR_INIT ("runscripts", "Yes", 0, CV_YesNo, NULL); -consvar_t cv_pause = CVAR_INIT ("pausepermission", "Server", CV_NETVAR, pause_cons_t, NULL); +consvar_t cv_pause = CVAR_INIT ("pausepermission", "Server", CV_SAVE|CV_NETVAR, pause_cons_t, NULL); consvar_t cv_mute = CVAR_INIT ("mute", "Off", CV_NETVAR|CV_CALL, CV_OnOff, Mute_OnChange); consvar_t cv_sleep = CVAR_INIT ("cpusleep", "1", CV_SAVE, sleeping_cons_t, NULL); @@ -3241,97 +3241,130 @@ static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum) */ static void Command_Addfile(void) { - const char *fn, *p; - char buf[256]; - char *buf_p = buf; - INT32 i; - int musiconly; // W_VerifyNMUSlumps isn't boolean + size_t argc = COM_Argc(); // amount of arguments total + size_t curarg; // current argument index - if (COM_Argc() != 2) + const char *addedfiles[argc]; // list of filenames already processed + size_t numfilesadded = 0; // the amount of filenames processed + + if (argc < 2) { - CONS_Printf(M_GetText("addfile : load wad file\n")); - return; - } - else - fn = COM_Argv(1); - - // Disallow non-printing characters and semicolons. - for (i = 0; fn[i] != '\0'; i++) - if (!isprint(fn[i]) || fn[i] == ';') - return; - - musiconly = W_VerifyNMUSlumps(fn); - - if (!musiconly) - { - // ... But only so long as they contain nothing more then music and sprites. - if (netgame && !(server || IsPlayerAdmin(consoleplayer))) - { - CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); - return; - } - G_SetGameModified(multiplayer); - } - - // Add file on your client directly if it is trivial, or you aren't in a netgame. - if (!(netgame || multiplayer) || musiconly) - { - P_AddWadFile(fn); + CONS_Printf(M_GetText("addfile [filename2...] [...]: Load add-ons\n")); return; } - p = fn+strlen(fn); - while(--p >= fn) - if (*p == '\\' || *p == '/' || *p == ':') - break; - ++p; - - // check total packet size and no of files currently loaded - // See W_LoadWadFile in w_wad.c - if ((numwadfiles >= MAX_WADFILES) - || ((packetsizetally + nameonlylength(fn) + 22) > MAXFILENEEDED*sizeof(UINT8))) + // start at one to skip command name + for (curarg = 1; curarg < argc; curarg++) { - CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn); - return; - } + const char *fn, *p; + char buf[256]; + char *buf_p = buf; + INT32 i; + size_t ii; + int musiconly; // W_VerifyNMUSlumps isn't boolean + boolean fileadded = false; - WRITESTRINGN(buf_p,p,240); + fn = COM_Argv(curarg); - // calculate and check md5 - { - UINT8 md5sum[16]; -#ifdef NOMD5 - memset(md5sum,0,16); -#else - FILE *fhandle; - - if ((fhandle = W_OpenWadFile(&fn, true)) != NULL) + // For the amount of filenames previously processed... + for (ii = 0; ii < numfilesadded; ii++) { - tic_t t = I_GetTime(); - CONS_Debug(DBG_SETUP, "Making MD5 for %s\n",fn); - md5_stream(fhandle, md5sum); - CONS_Debug(DBG_SETUP, "MD5 calc for %s took %f second\n", fn, (float)(I_GetTime() - t)/TICRATE); - fclose(fhandle); - } - else // file not found - return; - - for (i = 0; i < numwadfiles; i++) - { - if (!memcmp(wadfiles[i]->md5sum, md5sum, 16)) + // If this is one of them, don't try to add it. + if (!strcmp(fn, addedfiles[ii])) { - CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), fn); - return; + fileadded = true; + break; } } -#endif - WRITEMEM(buf_p, md5sum, 16); - } - if (IsPlayerAdmin(consoleplayer) && (!server)) // Request to add file - SendNetXCmd(XD_REQADDFILE, buf, buf_p - buf); - else - SendNetXCmd(XD_ADDFILE, buf, buf_p - buf); + // If we've added this one, skip to the next one. + if (fileadded) + { + CONS_Alert(CONS_WARNING, M_GetText("Already processed %s, skipping\n"), fn); + continue; + } + + // Disallow non-printing characters and semicolons. + for (i = 0; fn[i] != '\0'; i++) + if (!isprint(fn[i]) || fn[i] == ';') + return; + + musiconly = W_VerifyNMUSlumps(fn); + + if (!musiconly) + { + // ... But only so long as they contain nothing more then music and sprites. + if (netgame && !(server || IsPlayerAdmin(consoleplayer))) + { + CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); + continue; + } + G_SetGameModified(multiplayer); + } + + // Add file on your client directly if it is trivial, or you aren't in a netgame. + if (!(netgame || multiplayer) || musiconly) + { + P_AddWadFile(fn); + addedfiles[numfilesadded++] = fn; + continue; + } + + p = fn+strlen(fn); + while(--p >= fn) + if (*p == '\\' || *p == '/' || *p == ':') + break; + ++p; + + // check total packet size and no of files currently loaded + // See W_LoadWadFile in w_wad.c + if ((numwadfiles >= MAX_WADFILES) + || ((packetsizetally + nameonlylength(fn) + 22) > MAXFILENEEDED*sizeof(UINT8))) + { + CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn); + return; + } + + WRITESTRINGN(buf_p,p,240); + + // calculate and check md5 + { + UINT8 md5sum[16]; +#ifdef NOMD5 + memset(md5sum,0,16); +#else + FILE *fhandle; + + if ((fhandle = W_OpenWadFile(&fn, true)) != NULL) + { + tic_t t = I_GetTime(); + CONS_Debug(DBG_SETUP, "Making MD5 for %s\n",fn); + md5_stream(fhandle, md5sum); + CONS_Debug(DBG_SETUP, "MD5 calc for %s took %f second\n", fn, (float)(I_GetTime() - t)/TICRATE); + fclose(fhandle); + } + else // file not found + continue; + + for (i = 0; i < numwadfiles; i++) + { + if (!memcmp(wadfiles[i]->md5sum, md5sum, 16)) + { + CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), fn); + continue; + } + } +#endif + WRITEMEM(buf_p, md5sum, 16); + } + + addedfiles[numfilesadded++] = fn; + + if (IsPlayerAdmin(consoleplayer) && (!server)) // Request to add file + SendNetXCmd(XD_REQADDFILE, buf, buf_p - buf); + else + SendNetXCmd(XD_ADDFILE, buf, buf_p - buf); + } } static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) diff --git a/src/dehacked.c b/src/dehacked.c index c9a50e6d1..2ede2fd16 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -9908,6 +9908,25 @@ struct { {"FF_COLORMAPONLY",FF_COLORMAPONLY}, ///< Only copy the colormap, not the lightlevel {"FF_GOOWATER",FF_GOOWATER}, ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop. + // PolyObject flags + {"POF_CLIPLINES",POF_CLIPLINES}, ///< Test against lines for collision + {"POF_CLIPPLANES",POF_CLIPPLANES}, ///< Test against tops and bottoms for collision + {"POF_SOLID",POF_SOLID}, ///< Clips things. + {"POF_TESTHEIGHT",POF_TESTHEIGHT}, ///< Test line collision with heights + {"POF_RENDERSIDES",POF_RENDERSIDES}, ///< Renders the sides. + {"POF_RENDERTOP",POF_RENDERTOP}, ///< Renders the top. + {"POF_RENDERBOTTOM",POF_RENDERBOTTOM}, ///< Renders the bottom. + {"POF_RENDERPLANES",POF_RENDERPLANES}, ///< Renders top and bottom. + {"POF_RENDERALL",POF_RENDERALL}, ///< Renders everything. + {"POF_INVERT",POF_INVERT}, ///< Inverts collision (like a cage). + {"POF_INVERTPLANES",POF_INVERTPLANES}, ///< Render inside planes. + {"POF_INVERTPLANESONLY",POF_INVERTPLANESONLY}, ///< Only render inside planes. + {"POF_PUSHABLESTOP",POF_PUSHABLESTOP}, ///< Pushables will stop movement. + {"POF_LDEXEC",POF_LDEXEC}, ///< This PO triggers a linedef executor. + {"POF_ONESIDE",POF_ONESIDE}, ///< Only use the first side of the linedef. + {"POF_NOSPECIALS",POF_NOSPECIALS}, ///< Don't apply sector specials. + {"POF_SPLAT",POF_SPLAT}, ///< Use splat flat renderer (treat cyan pixels as invisible). + #ifdef HAVE_LUA_SEGS // Node flags {"NF_SUBSECTOR",NF_SUBSECTOR}, // Indicate a leaf. diff --git a/src/g_game.c b/src/g_game.c index f7c798b4b..1ea7cd080 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2019,7 +2019,7 @@ boolean G_Responder(event_t *ev) if (F_CreditResponder(ev)) { // Skip credits for everyone - if (! serverrunning)/* hahahahahaha */ + if (! netgame) F_StartGameEvaluation(); else if (server || IsPlayerAdmin(consoleplayer)) SendNetXCmd(XD_EXITLEVEL, NULL, 0); @@ -3518,7 +3518,7 @@ INT32 G_GetGametypeByName(const char *gametypestr) // boolean G_IsSpecialStage(INT32 mapnum) { - if (gametype != GT_COOP || modeattacking == ATTACKING_RECORD) + if (modeattacking == ATTACKING_RECORD) return false; if (mapnum >= sstage_start && mapnum <= sstage_end) return true; diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index a7f7acd22..607d21ef5 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -132,6 +132,43 @@ typedef struct FLOAT t; // t texture ordinate (t over w) } FOutVector; +#ifdef GL_SHADERS +// Predefined shader types +enum +{ + SHADER_DEFAULT = 0, + + SHADER_FLOOR, + SHADER_WALL, + SHADER_SPRITE, + SHADER_MODEL, SHADER_MODEL_LIGHTING, + SHADER_WATER, + SHADER_FOG, + SHADER_SKY, + + NUMBASESHADERS, +}; + +// Maximum amount of shader programs +// Must be higher than NUMBASESHADERS +#define HWR_MAXSHADERS 16 + +// Shader sources (vertex and fragment) +typedef struct +{ + char *vertex; + char *fragment; +} shadersource_t; + +// Custom shader reference table +typedef struct +{ + const char *type; + INT32 id; +} customshaderxlat_t; + +#endif + typedef struct vbo_vertex_s { float x, y, z; diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 4023e3062..aaa41e86f 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -68,14 +68,13 @@ EXPORT void HWRAPI(DrawScreenFinalTexture) (int width, int height); EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]); // jimita -EXPORT boolean HWRAPI(LoadShaders) (void); -EXPORT void HWRAPI(KillShaders) (void); +EXPORT boolean HWRAPI(CompileShaders) (void); +EXPORT void HWRAPI(CleanShaders) (void); EXPORT void HWRAPI(SetShader) (int shader); EXPORT void HWRAPI(UnSetShader) (void); EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value); -EXPORT void HWRAPI(LoadCustomShader) (int number, char *shader, size_t size, boolean fragment); -EXPORT boolean HWRAPI(InitCustomShaders) (void); +EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boolean isfragment); // ========================================================================== // HWR DRIVER OBJECT, FOR CLIENT PROGRAM @@ -120,14 +119,13 @@ struct hwdriver_s MakeScreenFinalTexture pfnMakeScreenFinalTexture; DrawScreenFinalTexture pfnDrawScreenFinalTexture; - LoadShaders pfnLoadShaders; - KillShaders pfnKillShaders; + CompileShaders pfnCompileShaders; + CleanShaders pfnCleanShaders; SetShader pfnSetShader; UnSetShader pfnUnSetShader; SetShaderInfo pfnSetShaderInfo; LoadCustomShader pfnLoadCustomShader; - InitCustomShaders pfnInitCustomShaders; }; extern struct hwdriver_s hwdriver; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 991b51aee..e7a0ac3ff 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -565,11 +565,11 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool PolyFlags |= PF_Masked|PF_Modulated; if (PolyFlags & PF_Fog) - shader = 6; // fog shader + shader = SHADER_FOG; // fog shader else if (PolyFlags & PF_Ripple) - shader = 5; // water shader + shader = SHADER_WATER; // water shader else - shader = 1; // floor shader + shader = SHADER_FLOOR; // floor shader HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, PolyFlags, shader, false); @@ -766,7 +766,7 @@ static void HWR_DrawSegsSplats(FSurfaceInfo * pSurf) break; } - HWD.pfnSetShader(2); // wall shader + HWD.pfnSetShader(SHADER_WALL); // wall shader HWD.pfnDrawPolygon(&pSurf, wallVerts, 4, i|PF_Modulated|PF_Decal); } } @@ -803,7 +803,7 @@ static void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIEL { HWR_Lighting(pSurf, lightlevel, wallcolormap); - HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode|PF_Modulated|PF_Occlude, 2, false); // wall shader + HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode|PF_Modulated|PF_Occlude, SHADER_WALL, false); // wall shader #ifdef WALLSPLATS if (gl_curline->linedef->splats && cv_splats.value) @@ -2843,7 +2843,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, else blendmode |= PF_Masked|PF_Modulated|PF_Clip; - HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, blendmode, 1, false); // floor shader + HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, blendmode, SHADER_FLOOR, false); // floor shader } static void HWR_AddPolyObjectPlanes(void) @@ -3655,7 +3655,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) HWR_Lighting(&sSurf, 0, colormap); sSurf.PolyColor.s.alpha = alpha; - HWR_ProcessPolygon(&sSurf, shadowVerts, 4, PF_Translucent|PF_Modulated|PF_Clip, 3, false); // sprite shader + HWR_ProcessPolygon(&sSurf, shadowVerts, 4, PF_Translucent|PF_Modulated|PF_Clip, SHADER_SPRITE, false); // sprite shader } // This is expecting a pointer to an array containing 4 wallVerts for a sprite @@ -3929,7 +3929,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) Surf.PolyColor.s.alpha = alpha; - HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, SHADER_SPRITE, false); // sprite shader if (use_linkdraw_hack) HWR_LinkDrawHackAdd(wallVerts, spr); @@ -3958,7 +3958,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) Surf.PolyColor.s.alpha = alpha; - HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, SHADER_SPRITE, false); // sprite shader if (use_linkdraw_hack) HWR_LinkDrawHackAdd(wallVerts, spr); @@ -4118,7 +4118,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) if (!occlusion) use_linkdraw_hack = true; } - HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, SHADER_SPRITE, false); // sprite shader if (use_linkdraw_hack) HWR_LinkDrawHackAdd(wallVerts, spr); @@ -4220,7 +4220,7 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) blend = PF_Translucent|PF_Occlude; } - HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, 3, false); // sprite shader + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, SHADER_SPRITE, false); // sprite shader } #endif @@ -4563,7 +4563,7 @@ static void HWR_CreateDrawNodes(void) // Okay! Let's draw it all! Woo! HWD.pfnSetTransform(&atransform); - HWD.pfnSetShader(0); + HWD.pfnSetShader(SHADER_DEFAULT); for (i = 0; i < p; i++) { @@ -5383,7 +5383,7 @@ static void HWR_DrawSkyBackground(player_t *player) HWR_BuildSkyDome(); } - HWD.pfnSetShader(7); // sky shader + HWD.pfnSetShader(SHADER_SKY); // sky shader HWD.pfnSetTransform(&dometransform); HWD.pfnRenderSkyDome(&gl_sky); } @@ -5470,7 +5470,7 @@ static void HWR_DrawSkyBackground(player_t *player) HWD.pfnDrawPolygon(NULL, v, 4, 0); } - HWD.pfnSetShader(0); + HWD.pfnSetShader(SHADER_DEFAULT); } @@ -5674,7 +5674,7 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) // Reset the shader state. HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_glshaders.value); - HWD.pfnSetShader(0); + HWD.pfnSetShader(SHADER_DEFAULT); validcount++; @@ -5887,7 +5887,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) // Reset the shader state. HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_glshaders.value); - HWD.pfnSetShader(0); + HWD.pfnSetShader(SHADER_DEFAULT); rs_numbspcalls = 0; rs_numpolyobjects = 0; @@ -6090,7 +6090,6 @@ void HWR_Startup(void) // do this once if (!startupdone) { - INT32 i; CONS_Printf("HWR_Startup()...\n"); HWR_InitPolyPool(); @@ -6101,10 +6100,8 @@ void HWR_Startup(void) HWR_InitLight(); #endif - // read every custom shader - for (i = 0; i < numwadfiles; i++) - HWR_ReadShaders(i, (wadfiles[i]->type == RET_PK3)); - if (!HWR_LoadShaders()) + HWR_LoadAllCustomShaders(); + if (!HWR_CompileShaders()) gl_shadersavailable = false; } @@ -6196,7 +6193,7 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, pSurf->PolyColor.s.alpha = alpha; // put the alpha back after lighting - shader = 2; // wall shader + shader = SHADER_WALL; // wall shader if (blend & PF_Environment) blendmode |= PF_Occlude; // PF_Occlude must be used for solid objects @@ -6204,7 +6201,7 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, if (fogwall) { blendmode |= PF_Fog; - shader = 6; // fog shader + shader = SHADER_FOG; // fog shader } blendmode |= PF_Modulated; // No PF_Occlude means overlapping (incorrect) transparency @@ -6389,13 +6386,7 @@ void HWR_DrawScreenFinalTexture(int width, int height) } // jimita 18032019 -typedef struct -{ - char type[16]; - INT32 id; -} shaderxlat_t; - -static inline UINT16 HWR_CheckShader(UINT16 wadnum) +static inline UINT16 HWR_FindShaderDefs(UINT16 wadnum) { UINT16 i; lumpinfo_t *lump_p; @@ -6408,12 +6399,34 @@ static inline UINT16 HWR_CheckShader(UINT16 wadnum) return INT16_MAX; } -boolean HWR_LoadShaders(void) +boolean HWR_CompileShaders(void) { - return HWD.pfnInitCustomShaders(); + return HWD.pfnCompileShaders(); } -void HWR_ReadShaders(UINT16 wadnum, boolean PK3) +customshaderxlat_t shaderxlat[] = +{ + {"Flat", SHADER_FLOOR}, + {"WallTexture", SHADER_WALL}, + {"Sprite", SHADER_SPRITE}, + {"Model", SHADER_MODEL}, + {"ModelLighting", SHADER_MODEL_LIGHTING}, + {"WaterRipple", SHADER_WATER}, + {"Fog", SHADER_FOG}, + {"Sky", SHADER_SKY}, + {NULL, 0}, +}; + +void HWR_LoadAllCustomShaders(void) +{ + INT32 i; + + // read every custom shader + for (i = 0; i < numwadfiles; i++) + HWR_LoadCustomShadersFromFile(i, (wadfiles[i]->type == RET_PK3)); +} + +void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3) { UINT16 lump; char *shaderdef, *line; @@ -6424,19 +6437,7 @@ void HWR_ReadShaders(UINT16 wadnum, boolean PK3) int shadertype = 0; int i; - #define SHADER_TYPES 7 - shaderxlat_t shaderxlat[SHADER_TYPES] = - { - {"Flat", 1}, - {"WallTexture", 2}, - {"Sprite", 3}, - {"Model", 4}, - {"WaterRipple", 5}, - {"Fog", 6}, - {"Sky", 7}, - }; - - lump = HWR_CheckShader(wadnum); + lump = HWR_FindShaderDefs(wadnum); if (lump == INT16_MAX) return; @@ -6462,7 +6463,7 @@ void HWR_ReadShaders(UINT16 wadnum, boolean PK3) value = strtok(NULL, "\r\n "); if (!value) { - CONS_Alert(CONS_WARNING, "HWR_ReadShaders: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); + CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); stoken = strtok(NULL, "\r\n"); // skip end of line goto skip_lump; } @@ -6481,19 +6482,19 @@ skip_lump: value = strtok(NULL, "\r\n= "); if (!value) { - CONS_Alert(CONS_WARNING, "HWR_ReadShaders: Missing shader target (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); + CONS_Alert(CONS_WARNING, "HWR_LoadCustomShadersFromFile: Missing shader target (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); stoken = strtok(NULL, "\r\n"); // skip end of line goto skip_field; } if (!shadertype) { - CONS_Alert(CONS_ERROR, "HWR_ReadShaders: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); + CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader type (file %s, line %d)\n", wadfiles[wadnum]->filename, linenum); Z_Free(line); return; } - for (i = 0; i < SHADER_TYPES; i++) + for (i = 0; shaderxlat[i].type; i++) { if (!stricmp(shaderxlat[i].type, stoken)) { @@ -6519,7 +6520,7 @@ skip_lump: if (shader_lumpnum == INT16_MAX) { - CONS_Alert(CONS_ERROR, "HWR_ReadShaders: Missing shader source %s (file %s, line %d)\n", shader_lumpname, wadfiles[wadnum]->filename, linenum); + CONS_Alert(CONS_ERROR, "HWR_LoadCustomShadersFromFile: Missing shader source %s (file %s, line %d)\n", shader_lumpname, wadfiles[wadnum]->filename, linenum); Z_Free(shader_lumpname); continue; } @@ -6545,4 +6546,22 @@ skip_field: return; } +const char *HWR_GetShaderName(INT32 shader) +{ + INT32 i; + + if (shader) + { + for (i = 0; shaderxlat[i].type; i++) + { + if (shaderxlat[i].id == shader) + return shaderxlat[i].type; + } + + return "Unknown"; + } + + return "Default"; +} + #endif // HWRENDER diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index d70bb6d72..9bce49b25 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -70,8 +70,13 @@ void HWR_DrawScreenFinalTexture(int width, int height); void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap); UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap); // Let's see if this can work -void HWR_ReadShaders(UINT16 wadnum, boolean PK3); -boolean HWR_LoadShaders(void); +boolean HWR_CompileShaders(void); + +void HWR_LoadAllCustomShaders(void); +void HWR_LoadCustomShadersFromFile(UINT16 wadnum, boolean PK3); +const char *HWR_GetShaderName(INT32 shader); + +extern customshaderxlat_t shaderxlat[]; extern CV_PossibleValue_t granisotropicmode_cons_t[]; diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 5f5130896..b0bf96480 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1572,7 +1572,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) p.mirror = atransform.mirror; // from Kart #endif - HWD.pfnSetShader(4); // model shader + HWD.pfnSetShader(SHADER_MODEL); // model shader HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, finalscale, flip, hflip, &Surf); } diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 6286da3a3..db3c6a17d 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -91,9 +91,10 @@ static GLuint startScreenWipe = 0; static GLuint endScreenWipe = 0; static GLuint finalScreenTexture = 0; -// Lactozilla: Set shader programs and uniforms +// Lactozilla: Shader functions static void *Shader_Load(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); +static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum); static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f}; @@ -578,15 +579,12 @@ static PFNglUniform2fv pglUniform2fv; static PFNglUniform3fv pglUniform3fv; static PFNglGetUniformLocation pglGetUniformLocation; -#define MAXSHADERS 16 -#define MAXSHADERPROGRAMS 16 - // 18032019 -static char *gl_customvertexshaders[MAXSHADERS]; -static char *gl_customfragmentshaders[MAXSHADERS]; static GLuint gl_currentshaderprogram = 0; static boolean gl_shaderprogramchanged = true; +static shadersource_t gl_customshaders[HWR_MAXSHADERS]; + // 13062019 typedef enum { @@ -610,17 +608,59 @@ typedef struct gl_shaderprogram_s boolean custom; GLint uniforms[gluniform_max+1]; } gl_shaderprogram_t; -static gl_shaderprogram_t gl_shaderprograms[MAXSHADERPROGRAMS]; +static gl_shaderprogram_t gl_shaderprograms[HWR_MAXSHADERS]; // Shader info static INT32 shader_leveltime = 0; -// ======================== -// Fragment shader macros -// ======================== +// ================ +// Vertex shaders +// ================ // -// GLSL Software fragment shader +// Generic vertex shader +// + +#define GLSL_DEFAULT_VERTEX_SHADER \ + "void main()\n" \ + "{\n" \ + "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ + "gl_FrontColor = gl_Color;\n" \ + "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ + "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ + "}\0" + +// replicates the way fixed function lighting is used by the model lighting option, +// stores the lighting result to gl_Color +// (ambient lighting of 0.75 and diffuse lighting from above) +#define GLSL_MODEL_LIGHTING_VERTEX_SHADER \ + "void main()\n" \ + "{\n" \ + "float nDotVP = dot(gl_Normal, vec3(0, 1, 0));\n" \ + "float light = 0.75 + max(nDotVP, 0.0);\n" \ + "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ + "gl_FrontColor = vec4(light, light, light, 1.0);\n" \ + "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ + "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ + "}\0" + +// ================== +// Fragment shaders +// ================== + +// +// Generic fragment shader +// + +#define GLSL_DEFAULT_FRAGMENT_SHADER \ + "uniform sampler2D tex;\n" \ + "uniform vec4 poly_color;\n" \ + "void main(void) {\n" \ + "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \ + "}\0" + +// +// Software fragment shader // #define GLSL_DOOM_COLORMAP \ @@ -761,22 +801,10 @@ static INT32 shader_leveltime = 0; "gl_FragColor = final_color;\n" \ "}\0" -// -// GLSL generic fragment shader -// - -#define GLSL_DEFAULT_FRAGMENT_SHADER \ - "uniform sampler2D tex;\n" \ - "uniform vec4 poly_color;\n" \ - "void main(void) {\n" \ - "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * poly_color;\n" \ - "}\0" - // // Sky fragment shader // Modulates poly_color with gl_Color // - #define GLSL_SKY_FRAGMENT_SHADER \ "uniform sampler2D tex;\n" \ "uniform vec4 poly_color;\n" \ @@ -784,97 +812,42 @@ static INT32 shader_leveltime = 0; "gl_FragColor = texture2D(tex, gl_TexCoord[0].st) * gl_Color * poly_color;\n" \ "}\0" -static const char *fragment_shaders[] = { - // Default fragment shader - GLSL_DEFAULT_FRAGMENT_SHADER, +// ================ +// Shader sources +// ================ - // Floor fragment shader - GLSL_SOFTWARE_FRAGMENT_SHADER, +static struct { + const char *vertex; + const char *fragment; +} const gl_shadersources[] = { + // Default shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_DEFAULT_FRAGMENT_SHADER}, - // Wall fragment shader - GLSL_SOFTWARE_FRAGMENT_SHADER, + // Floor shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, - // Sprite fragment shader - GLSL_SOFTWARE_FRAGMENT_SHADER, + // Wall shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, - // Model fragment shader - GLSL_SOFTWARE_FRAGMENT_SHADER, + // Sprite shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, - // Water fragment shader - GLSL_WATER_FRAGMENT_SHADER, + // Model shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SOFTWARE_FRAGMENT_SHADER}, - // Fog fragment shader - GLSL_FOG_FRAGMENT_SHADER, + // Model shader + diffuse lighting from above + {GLSL_MODEL_LIGHTING_VERTEX_SHADER, GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER}, - // Sky fragment shader - GLSL_SKY_FRAGMENT_SHADER, + // Water shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_WATER_FRAGMENT_SHADER}, - // Model fragment shader + diffuse lighting from above - GLSL_SOFTWARE_MODEL_LIGHTING_FRAGMENT_SHADER, + // Fog shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_FOG_FRAGMENT_SHADER}, - NULL, -}; + // Sky shader + {GLSL_DEFAULT_VERTEX_SHADER, GLSL_SKY_FRAGMENT_SHADER}, -// ====================== -// Vertex shader macros -// ====================== - -// -// GLSL generic vertex shader -// - -#define GLSL_DEFAULT_VERTEX_SHADER \ - "void main()\n" \ - "{\n" \ - "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ - "gl_FrontColor = gl_Color;\n" \ - "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ - "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ - "}\0" - -// replicates the way fixed function lighting is used by the model lighting option, -// stores the lighting result to gl_Color -// (ambient lighting of 0.75 and diffuse lighting from above) -#define GLSL_MODEL_LIGHTING_VERTEX_SHADER \ - "void main()\n" \ - "{\n" \ - "float nDotVP = dot(gl_Normal, vec3(0, 1, 0));\n" \ - "float light = 0.75 + max(nDotVP, 0.0);\n" \ - "gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n" \ - "gl_FrontColor = vec4(light, light, light, 1.0);\n" \ - "gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;\n" \ - "gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n" \ - "}\0" - -static const char *vertex_shaders[] = { - // Default vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Floor vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Wall vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Sprite vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Model vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Water vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Fog vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Sky vertex shader - GLSL_DEFAULT_VERTEX_SHADER, - - // Model vertex shader + diffuse lighting from above - GLSL_MODEL_LIGHTING_VERTEX_SHADER, - - NULL, + {NULL, NULL}, }; #endif // GL_SHADERS @@ -920,7 +893,7 @@ void SetupGLFunc4(void) } // jimita -EXPORT boolean HWRAPI(LoadShaders) (void) +EXPORT boolean HWRAPI(CompileShaders) (void) { #ifdef GL_SHADERS GLuint gl_vertShader, gl_fragShader; @@ -928,25 +901,23 @@ EXPORT boolean HWRAPI(LoadShaders) (void) if (!pglUseProgram) return false; - gl_customvertexshaders[0] = NULL; - gl_customfragmentshaders[0] = NULL; + gl_customshaders[0].vertex = NULL; + gl_customshaders[0].fragment = NULL; - for (i = 0; vertex_shaders[i] && fragment_shaders[i]; i++) + for (i = 0; gl_shadersources[i].vertex && gl_shadersources[i].fragment; i++) { gl_shaderprogram_t *shader; - const GLchar* vert_shader = vertex_shaders[i]; - const GLchar* frag_shader = fragment_shaders[i]; - boolean custom = ((gl_customvertexshaders[i] || gl_customfragmentshaders[i]) && (i > 0)); + const GLchar *vert_shader = gl_shadersources[i].vertex; + const GLchar *frag_shader = gl_shadersources[i].fragment; + boolean custom = ((gl_customshaders[i].vertex || gl_customshaders[i].fragment) && (i > 0)); // 18032019 - if (gl_customvertexshaders[i]) - vert_shader = gl_customvertexshaders[i]; - if (gl_customfragmentshaders[i]) - frag_shader = gl_customfragmentshaders[i]; + if (gl_customshaders[i].vertex) + vert_shader = gl_customshaders[i].vertex; + if (gl_customshaders[i].fragment) + frag_shader = gl_customshaders[i].fragment; - if (i >= MAXSHADERS) - break; - if (i >= MAXSHADERPROGRAMS) + if (i >= HWR_MAXSHADERS) break; shader = &gl_shaderprograms[i]; @@ -959,7 +930,7 @@ EXPORT boolean HWRAPI(LoadShaders) (void) gl_vertShader = pglCreateShader(GL_VERTEX_SHADER); if (!gl_vertShader) { - GL_MSG_Error("LoadShaders: Error creating vertex shader %d\n", i); + GL_MSG_Error("CompileShaders: Error creating vertex shader %s\n", HWR_GetShaderName(i)); continue; } @@ -970,15 +941,7 @@ EXPORT boolean HWRAPI(LoadShaders) (void) pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result); if (result == GL_FALSE) { - GLchar* infoLog; - GLint logLength; - - pglGetShaderiv(gl_vertShader, GL_INFO_LOG_LENGTH, &logLength); - - infoLog = malloc(logLength); - pglGetShaderInfoLog(gl_vertShader, logLength, NULL, infoLog); - - GL_MSG_Error("LoadShaders: Error compiling vertex shader %d\n%s", i, infoLog); + Shader_CompileError("Error compiling vertex shader", gl_vertShader, i); continue; } @@ -988,7 +951,7 @@ EXPORT boolean HWRAPI(LoadShaders) (void) gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER); if (!gl_fragShader) { - GL_MSG_Error("LoadShaders: Error creating fragment shader %d\n", i); + GL_MSG_Error("CompileShaders: Error creating fragment shader %s\n", HWR_GetShaderName(i)); continue; } @@ -999,15 +962,7 @@ EXPORT boolean HWRAPI(LoadShaders) (void) pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result); if (result == GL_FALSE) { - GLchar* infoLog; - GLint logLength; - - pglGetShaderiv(gl_fragShader, GL_INFO_LOG_LENGTH, &logLength); - - infoLog = malloc(logLength); - pglGetShaderInfoLog(gl_fragShader, logLength, NULL, infoLog); - - GL_MSG_Error("LoadShaders: Error compiling fragment shader %d\n%s", i, infoLog); + Shader_CompileError("Error compiling fragment shader", gl_fragShader, i); continue; } @@ -1028,7 +983,7 @@ EXPORT boolean HWRAPI(LoadShaders) (void) { shader->program = 0; shader->custom = false; - GL_MSG_Error("LoadShaders: Error linking shader program %d\n", i); + GL_MSG_Error("CompileShaders: Error linking shader program %s\n", HWR_GetShaderName(i)); continue; } @@ -1048,8 +1003,10 @@ EXPORT boolean HWRAPI(LoadShaders) (void) #undef GETUNI } -#endif return true; +#else + return false; +#endif } // @@ -1077,25 +1034,34 @@ EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value) // // Custom shader loading // -EXPORT void HWRAPI(LoadCustomShader) (int number, char *shader, size_t size, boolean fragment) +EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boolean isfragment) { #ifdef GL_SHADERS - if (!pglUseProgram) return; - if (number < 1 || number > MAXSHADERS) - I_Error("LoadCustomShader(): cannot load shader %d (max %d)", number, MAXSHADERS); + shadersource_t *shader; - if (fragment) - { - gl_customfragmentshaders[number] = malloc(size+1); - strncpy(gl_customfragmentshaders[number], shader, size); - gl_customfragmentshaders[number][size] = 0; + if (!pglUseProgram) + return; + + if (number < 1 || number > HWR_MAXSHADERS) + I_Error("LoadCustomShader: cannot load shader %d (min 1, max %d)", number, HWR_MAXSHADERS); + else if (code == NULL) + I_Error("LoadCustomShader: empty shader"); + + shader = &gl_customshaders[number]; + +#define COPYSHADER(source) { \ + if (shader->source) \ + free(shader->source); \ + shader->source = malloc(size+1); \ + strncpy(shader->source, code, size); \ + shader->source[size] = 0; \ } + + if (isfragment) + COPYSHADER(fragment) else - { - gl_customvertexshaders[number] = malloc(size+1); - strncpy(gl_customvertexshaders[number], shader, size); - gl_customvertexshaders[number][size] = 0; - } + COPYSHADER(vertex) + #else (void)number; (void)shader; @@ -1104,14 +1070,6 @@ EXPORT void HWRAPI(LoadCustomShader) (int number, char *shader, size_t size, boo #endif } -EXPORT boolean HWRAPI(InitCustomShaders) (void) -{ -#ifdef GL_SHADERS - KillShaders(); - return LoadShaders(); -#endif -} - EXPORT void HWRAPI(SetShader) (int shader) { #ifdef GL_SHADERS @@ -1119,9 +1077,9 @@ EXPORT void HWRAPI(SetShader) (int shader) { // If using model lighting, set the appropriate shader. // However don't override a custom shader. - // Should use an enum or something... - if (shader == 4 && model_lighting && !gl_shaderprograms[4].custom) - shader = 8; + if (shader == SHADER_MODEL && model_lighting + && !(gl_shaderprograms[SHADER_MODEL].custom && !gl_shaderprograms[SHADER_MODEL_LIGHTING].custom)) + shader = SHADER_MODEL_LIGHTING; if ((GLuint)shader != gl_currentshaderprogram) { gl_currentshaderprogram = shader; @@ -1146,9 +1104,23 @@ EXPORT void HWRAPI(UnSetShader) (void) #endif } -EXPORT void HWRAPI(KillShaders) (void) +EXPORT void HWRAPI(CleanShaders) (void) { - // unused......................... + INT32 i; + + for (i = 1; i < HWR_MAXSHADERS; i++) + { + shadersource_t *shader = &gl_customshaders[i]; + + if (shader->vertex) + free(shader->vertex); + + if (shader->fragment) + free(shader->fragment); + + shader->vertex = NULL; + shader->fragment = NULL; + } } // -----------------+ @@ -2017,6 +1989,25 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF #endif } +static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum) +{ + GLchar *infoLog = NULL; + GLint logLength; + + pglGetShaderiv(program, GL_INFO_LOG_LENGTH, &logLength); + + if (logLength) + { + infoLog = malloc(logLength); + pglGetShaderInfoLog(program, logLength, NULL, infoLog); + } + + GL_MSG_Error("CompileShaders: %s (%s)\n%s", message, HWR_GetShaderName(shadernum), (infoLog ? infoLog : "")); + + if (infoLog) + free(infoLog); +} + // code that is common between DrawPolygon and DrawIndexedTriangles // the corona thing is there too, i have no idea if that stuff works with DrawIndexedTriangles and batching static void PreparePolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FBITFIELD PolyFlags) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index d74af4214..132ebc1a8 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -173,8 +173,13 @@ static const struct { {META_SEG, "seg_t"}, {META_NODE, "node_t"}, #endif + {META_SLOPE, "slope_t"}, + {META_VECTOR2, "vector2_t"}, + {META_VECTOR3, "vector3_t"}, {META_MAPHEADER, "mapheader_t"}, + {META_POLYOBJ, "polyobj_t"}, + {META_CVAR, "consvar_t"}, {META_SECTORLINES, "sector_t.lines"}, @@ -1730,6 +1735,18 @@ static int lib_pFloorzAtPos(lua_State *L) return 1; } +static int lib_pCeilingzAtPos(lua_State *L) +{ + fixed_t x = luaL_checkfixed(L, 1); + fixed_t y = luaL_checkfixed(L, 2); + fixed_t z = luaL_checkfixed(L, 3); + fixed_t height = luaL_checkfixed(L, 4); + //HUDSAFE + INLEVEL + lua_pushfixed(L, P_CeilingzAtPos(x, y, z, height)); + return 1; +} + static int lib_pDoSpring(lua_State *L) { mobj_t *spring = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -3604,6 +3621,7 @@ static luaL_Reg lib[] = { {"P_CheckHoopPosition",lib_pCheckHoopPosition}, {"P_RadiusAttack",lib_pRadiusAttack}, {"P_FloorzAtPos",lib_pFloorzAtPos}, + {"P_CeilingzAtPos",lib_pCeilingzAtPos}, {"P_DoSpring",lib_pDoSpring}, // p_inter diff --git a/src/lua_blockmaplib.c b/src/lua_blockmaplib.c index 5aae73284..1949d56bb 100644 --- a/src/lua_blockmaplib.c +++ b/src/lua_blockmaplib.c @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2016 by Iestyn "Monster Iestyn" Jealous. +// Copyright (C) 2016-2020 by Iestyn "Monster Iestyn" Jealous. // Copyright (C) 2016-2020 by Sonic Team Junior. // // This program is free software distributed under the @@ -13,6 +13,7 @@ #include "doomdef.h" #include "p_local.h" #include "r_main.h" // validcount +#include "p_polyobj.h" #include "lua_script.h" #include "lua_libs.h" //#include "lua_hud.h" // hud_running errors @@ -20,6 +21,7 @@ static const char *const search_opt[] = { "objects", "lines", + "polyobjs", NULL}; // a quickly-made function pointer typedef used by lib_searchBlockmap... @@ -167,6 +169,55 @@ static UINT8 lib_searchBlockmap_Lines(lua_State *L, INT32 x, INT32 y, mobj_t *th return 0; // Everything was checked. } +// Helper function for "polyobjs" search +static UINT8 lib_searchBlockmap_PolyObjs(lua_State *L, INT32 x, INT32 y, mobj_t *thing) +{ + INT32 offset; + polymaplink_t *plink; // haleyjd 02/22/06 + + if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight) + return 0; + + offset = y*bmapwidth + x; + + // haleyjd 02/22/06: consider polyobject lines + plink = polyblocklinks[offset]; + + while (plink) + { + polyobj_t *po = plink->po; + + if (po->validcount != validcount) // if polyobj hasn't been checked + { + po->validcount = validcount; + + lua_pushvalue(L, 1); + LUA_PushUserdata(L, thing, META_MOBJ); + LUA_PushUserdata(L, po, META_POLYOBJ); + if (lua_pcall(gL, 2, 1, 0)) { + if (!blockfuncerror || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + blockfuncerror = true; + return 0; // *shrugs* + } + if (!lua_isnil(gL, -1)) + { // if nil, continue + if (lua_toboolean(gL, -1)) + return 2; // stop whole search + else + return 1; // stop block search + } + lua_pop(gL, 1); + if (P_MobjWasRemoved(thing)) + return 2; + } + plink = (polymaplink_t *)(plink->link.next); + } + + return 0; // Everything was checked. +} + // The searchBlockmap function // arguments: searchBlockmap(searchtype, function, mobj, [x1, x2, y1, y2]) // return value: @@ -195,6 +246,9 @@ static int lib_searchBlockmap(lua_State *L) case 1: // "lines" searchFunc = lib_searchBlockmap_Lines; break; + case 2: // "polyobjs" + searchFunc = lib_searchBlockmap_PolyObjs; + break; } // the mobj we are searching around, the "calling" mobj we could say diff --git a/src/lua_libs.h b/src/lua_libs.h index f987c79fd..03bd99cd2 100644 --- a/src/lua_libs.h +++ b/src/lua_libs.h @@ -50,6 +50,8 @@ extern lua_State *gL; #define META_VECTOR3 "VECTOR3_T" #define META_MAPHEADER "MAPHEADER_T*" +#define META_POLYOBJ "POLYOBJ_T*" + #define META_CVAR "CONSVAR_T*" #define META_SECTORLINES "SECTOR_T*LINES" @@ -58,6 +60,8 @@ extern lua_State *gL; #define META_LINESTRINGARGS "LINE_T*STRINGARGS" #define META_THINGARGS "MAPTHING_T*ARGS" #define META_THINGSTRINGARGS "MAPTHING_T*STRINGARGS" +#define META_POLYOBJVERTICES "POLYOBJ_T*VERTICES" +#define META_POLYOBJLINES "POLYOBJ_T*LINES" #ifdef HAVE_LUA_SEGS #define META_NODEBBOX "NODE_T*BBOX" #define META_NODECHILDREN "NODE_T*CHILDREN" @@ -88,5 +92,6 @@ int LUA_PlayerLib(lua_State *L); int LUA_SkinLib(lua_State *L); int LUA_ThinkerLib(lua_State *L); int LUA_MapLib(lua_State *L); +int LUA_PolyObjLib(lua_State *L); int LUA_BlockmapLib(lua_State *L); int LUA_HudLib(lua_State *L); diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 855ec9482..5f6dbc4d6 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -16,6 +16,7 @@ #include "p_setup.h" #include "z_zone.h" #include "p_slopes.h" +#include "p_polyobj.h" #include "r_main.h" #include "lua_script.h" @@ -68,6 +69,7 @@ enum subsector_e { subsector_sector, subsector_numlines, subsector_firstline, + subsector_polyList }; static const char *const subsector_opt[] = { @@ -75,6 +77,7 @@ static const char *const subsector_opt[] = { "sector", "numlines", "firstline", + "polyList", NULL}; enum line_e { @@ -98,6 +101,7 @@ enum line_e { line_backsector, line_firsttag, line_nexttag, + line_polyobj, line_text, line_callcount }; @@ -123,6 +127,7 @@ static const char *const line_opt[] = { "backsector", "firsttag", "nexttag", + "polyobj", "text", "callcount", NULL}; @@ -223,6 +228,7 @@ enum seg_e { seg_linedef, seg_frontsector, seg_backsector, + seg_polyseg }; static const char *const seg_opt[] = { @@ -236,6 +242,7 @@ static const char *const seg_opt[] = { "linedef", "frontsector", "backsector", + "polyseg", NULL}; enum node_e { @@ -325,9 +332,9 @@ static const char *const vector_opt[] = { static const char *const array_opt[] ={"iterate",NULL}; static const char *const valid_opt[] ={"valid",NULL}; -/////////////////////////////////// -// sector list iterate functions // -/////////////////////////////////// +///////////////////////////////////////////// +// sector/subsector list iterate functions // +///////////////////////////////////////////// // iterates through a sector's thinglist! static int lib_iterateSectorThinglist(lua_State *L) @@ -399,6 +406,41 @@ static int lib_iterateSectorFFloors(lua_State *L) return 0; } +// iterates through a subsector's polyList! (for polyobj_t) +static int lib_iterateSubSectorPolylist(lua_State *L) +{ + polyobj_t *state = NULL; + polyobj_t *po = NULL; + + INLEVEL + + if (lua_gettop(L) < 2) + return luaL_error(L, "Don't call subsector.polyList() directly, use it as 'for polyobj in subsector.polyList do end'."); + + if (!lua_isnil(L, 1)) + state = *((polyobj_t **)luaL_checkudata(L, 1, META_POLYOBJ)); + else + return 0; // no polylist to iterate through sorry! + + lua_settop(L, 2); + lua_remove(L, 1); // remove state now. + + if (!lua_isnil(L, 1)) + { + po = *((polyobj_t **)luaL_checkudata(L, 1, META_POLYOBJ)); + po = (polyobj_t *)(po->link.next); + } + else + po = state; // state is used as the "start" of the polylist + + if (po) + { + LUA_PushUserdata(L, po, META_POLYOBJ); + return 1; + } + return 0; +} + static int sector_iterate(lua_State *L) { lua_pushvalue(L, lua_upvalueindex(1)); // iterator function, or the "generator" @@ -687,6 +729,11 @@ static int subsector_get(lua_State *L) case subsector_firstline: lua_pushinteger(L, subsector->firstline); return 1; + case subsector_polyList: // polyList + lua_pushcfunction(L, lib_iterateSubSectorPolylist); + LUA_PushUserdata(L, subsector->polyList, META_POLYOBJ); + lua_pushcclosure(L, sector_iterate, 2); // push lib_iterateSubSectorPolylist and subsector->polyList as upvalues for the function + return 1; } return 0; } @@ -830,6 +877,9 @@ static int line_get(lua_State *L) case line_nexttag: lua_pushinteger(L, line->nexttag); return 1; + case line_polyobj: + LUA_PushUserdata(L, line->polyobj, META_POLYOBJ); + return 1; case line_text: lua_pushstring(L, line->text); return 1; @@ -1092,6 +1142,9 @@ static int seg_get(lua_State *L) case seg_backsector: LUA_PushUserdata(L, seg->backsector, META_SECTOR); return 1; + case seg_polyseg: + LUA_PushUserdata(L, seg->polyseg, META_POLYOBJ); + return 1; } return 0; } diff --git a/src/lua_polyobjlib.c b/src/lua_polyobjlib.c new file mode 100644 index 000000000..c4dfa8ae4 --- /dev/null +++ b/src/lua_polyobjlib.c @@ -0,0 +1,486 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2020 by Iestyn "Monster Iestyn" Jealous. +// Copyright (C) 2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file lua_polyobjlib.c +/// \brief polyobject library for Lua scripting + +#include "doomdef.h" +#include "fastcmp.h" +#include "p_local.h" +#include "p_polyobj.h" +#include "lua_script.h" +#include "lua_libs.h" +#include "lua_hud.h" // hud_running errors + +#define NOHUD if (hud_running)\ +return luaL_error(L, "HUD rendering code should not call this function!"); + +enum polyobj_e { + // properties + polyobj_valid = 0, + polyobj_id, + polyobj_parent, + polyobj_vertices, + polyobj_lines, + polyobj_sector, + polyobj_angle, + polyobj_damage, + polyobj_thrust, + polyobj_flags, + polyobj_translucency, + polyobj_triggertag, + // special functions - utility + polyobj_pointInside, + polyobj_mobjTouching, + polyobj_mobjInside, + // special functions - manipulation + polyobj_moveXY, + polyobj_rotate +}; +static const char *const polyobj_opt[] = { + // properties + "valid", + "id", + "parent", + "vertices", + "lines", + "sector", + "angle", + "damage", + "thrust", + "flags", + "translucency", + "triggertag", + // special functions - utility + "pointInside", + "mobjTouching", + "mobjInside", + // special functions - manipulation + "moveXY", + "rotate", + NULL}; + +static const char *const valid_opt[] ={"valid",NULL}; + +//////////////////////// +// polyobj.vertices[] // +//////////////////////// + +// polyobj.vertices, i -> polyobj.vertices[i] +// polyobj.vertices.valid, for validity checking +// +// see sectorlines_get in lua_maplib.c +// +static int polyobjvertices_get(lua_State *L) +{ + vertex_t ***polyverts = *((vertex_t ****)luaL_checkudata(L, 1, META_POLYOBJVERTICES)); + size_t i; + size_t numofverts = 0; + lua_settop(L, 2); + if (!lua_isnumber(L, 2)) + { + int field = luaL_checkoption(L, 2, NULL, valid_opt); + if (!polyverts || !(*polyverts)) + { + if (field == 0) { + lua_pushboolean(L, 0); + return 1; + } + return luaL_error(L, "accessed polyobj_t.vertices doesn't exist anymore."); + } else if (field == 0) { + lua_pushboolean(L, 1); + return 1; + } + } + + numofverts = (size_t)(*(size_t *)(((size_t)polyverts) - (offsetof(polyobj_t, vertices) - offsetof(polyobj_t, numVertices)))); + + if (!numofverts) + return luaL_error(L, "no vertices found!"); + + i = (size_t)lua_tointeger(L, 2); + if (i >= numofverts) + return 0; + LUA_PushUserdata(L, (*polyverts)[i], META_VERTEX); + return 1; +} + +// #(polyobj.vertices) -> polyobj.numVertices +static int polyobjvertices_num(lua_State *L) +{ + vertex_t ***polyverts = *((vertex_t ****)luaL_checkudata(L, 1, META_POLYOBJVERTICES)); + size_t numofverts = 0; + + if (!polyverts || !(*polyverts)) + return luaL_error(L, "accessed polyobj_t.vertices doesn't exist anymore."); + + numofverts = (size_t)(*(size_t *)(((size_t)polyverts) - (offsetof(polyobj_t, vertices) - offsetof(polyobj_t, numVertices)))); + lua_pushinteger(L, numofverts); + return 1; +} + +///////////////////// +// polyobj.lines[] // +///////////////////// + +// polyobj.lines, i -> polyobj.lines[i] +// polyobj.lines.valid, for validity checking +// +// see sectorlines_get in lua_maplib.c +// +static int polyobjlines_get(lua_State *L) +{ + line_t ***polylines = *((line_t ****)luaL_checkudata(L, 1, META_POLYOBJLINES)); + size_t i; + size_t numoflines = 0; + lua_settop(L, 2); + if (!lua_isnumber(L, 2)) + { + int field = luaL_checkoption(L, 2, NULL, valid_opt); + if (!polylines || !(*polylines)) + { + if (field == 0) { + lua_pushboolean(L, 0); + return 1; + } + return luaL_error(L, "accessed polyobj_t.lines doesn't exist anymore."); + } else if (field == 0) { + lua_pushboolean(L, 1); + return 1; + } + } + + numoflines = (size_t)(*(size_t *)(((size_t)polylines) - (offsetof(polyobj_t, lines) - offsetof(polyobj_t, numLines)))); + + if (!numoflines) + return luaL_error(L, "no lines found!"); + + i = (size_t)lua_tointeger(L, 2); + if (i >= numoflines) + return 0; + LUA_PushUserdata(L, (*polylines)[i], META_LINE); + return 1; +} + +// #(polyobj.lines) -> polyobj.numLines +static int polyobjlines_num(lua_State *L) +{ + line_t ***polylines = *((line_t ****)luaL_checkudata(L, 1, META_POLYOBJLINES)); + size_t numoflines = 0; + + if (!polylines || !(*polylines)) + return luaL_error(L, "accessed polyobj_t.lines doesn't exist anymore."); + + numoflines = (size_t)(*(size_t *)(((size_t)polylines) - (offsetof(polyobj_t, lines) - offsetof(polyobj_t, numLines)))); + lua_pushinteger(L, numoflines); + return 1; +} + +///////////////////////////////// +// polyobj_t function wrappers // +///////////////////////////////// + +// special functions - utility +static int lib_polyobj_PointInside(lua_State *L) +{ + polyobj_t *po = *((polyobj_t **)luaL_checkudata(L, 1, META_POLYOBJ)); + fixed_t x = luaL_checkfixed(L, 2); + fixed_t y = luaL_checkfixed(L, 3); + INLEVEL + if (!po) + return LUA_ErrInvalid(L, "polyobj_t"); + lua_pushboolean(L, P_PointInsidePolyobj(po, x, y)); + return 1; +} + +static int lib_polyobj_MobjTouching(lua_State *L) +{ + polyobj_t *po = *((polyobj_t **)luaL_checkudata(L, 1, META_POLYOBJ)); + mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); + INLEVEL + if (!po) + return LUA_ErrInvalid(L, "polyobj_t"); + if (!mo) + return LUA_ErrInvalid(L, "mobj_t"); + lua_pushboolean(L, P_MobjTouchingPolyobj(po, mo)); + return 1; +} + +static int lib_polyobj_MobjInside(lua_State *L) +{ + polyobj_t *po = *((polyobj_t **)luaL_checkudata(L, 1, META_POLYOBJ)); + mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); + INLEVEL + if (!po) + return LUA_ErrInvalid(L, "polyobj_t"); + if (!mo) + return LUA_ErrInvalid(L, "mobj_t"); + lua_pushboolean(L, P_MobjInsidePolyobj(po, mo)); + return 1; +} + +// special functions - manipulation +static int lib_polyobj_moveXY(lua_State *L) +{ + polyobj_t *po = *((polyobj_t **)luaL_checkudata(L, 1, META_POLYOBJ)); + fixed_t x = luaL_checkfixed(L, 2); + fixed_t y = luaL_checkfixed(L, 3); + boolean checkmobjs = lua_opttrueboolean(L, 4); + NOHUD + INLEVEL + if (!po) + return LUA_ErrInvalid(L, "polyobj_t"); + lua_pushboolean(L, Polyobj_moveXY(po, x, y, checkmobjs)); + return 1; +} + +static int lib_polyobj_rotate(lua_State *L) +{ + polyobj_t *po = *((polyobj_t **)luaL_checkudata(L, 1, META_POLYOBJ)); + angle_t delta = luaL_checkangle(L, 2); + UINT8 turnthings = (UINT8)luaL_optinteger(L, 3, 0); // don't turn anything by default? (could change this if not desired) + boolean checkmobjs = lua_opttrueboolean(L, 4); + NOHUD + INLEVEL + if (!po) + return LUA_ErrInvalid(L, "polyobj_t"); + lua_pushboolean(L, Polyobj_rotate(po, delta, turnthings, checkmobjs)); + return 1; +} + +/////////////// +// polyobj_t // +/////////////// + +static int polyobj_get(lua_State *L) +{ + polyobj_t *polyobj = *((polyobj_t **)luaL_checkudata(L, 1, META_POLYOBJ)); + enum polyobj_e field = luaL_checkoption(L, 2, NULL, polyobj_opt); + + if (!polyobj) { + if (field == polyobj_valid) { + lua_pushboolean(L, false); + return 1; + } + return LUA_ErrInvalid(L, "polyobj_t"); + } + + switch (field) + { + // properties + case polyobj_valid: + lua_pushboolean(L, true); + break; + case polyobj_id: + lua_pushinteger(L, polyobj->id); + break; + case polyobj_parent: + lua_pushinteger(L, polyobj->parent); + break; + case polyobj_vertices: // vertices + LUA_PushUserdata(L, &polyobj->vertices, META_POLYOBJVERTICES); // push the address of the "vertices" member in the struct, to allow our hacks to work + break; + case polyobj_lines: // lines + LUA_PushUserdata(L, &polyobj->lines, META_POLYOBJLINES); // push the address of the "lines" member in the struct, to allow our hacks to work + break; + case polyobj_sector: // shortcut that exists only in Lua! + LUA_PushUserdata(L, polyobj->lines[0]->backsector, META_SECTOR); + break; + case polyobj_angle: + lua_pushangle(L, polyobj->angle); + break; + case polyobj_damage: + lua_pushinteger(L, polyobj->damage); + break; + case polyobj_thrust: + lua_pushfixed(L, polyobj->thrust); + break; + case polyobj_flags: + lua_pushinteger(L, polyobj->flags); + break; + case polyobj_translucency: + lua_pushinteger(L, polyobj->translucency); + break; + case polyobj_triggertag: + lua_pushinteger(L, polyobj->triggertag); + break; + // special functions - utility + case polyobj_pointInside: + lua_pushcfunction(L, lib_polyobj_PointInside); + break; + case polyobj_mobjTouching: + lua_pushcfunction(L, lib_polyobj_MobjTouching); + break; + case polyobj_mobjInside: + lua_pushcfunction(L, lib_polyobj_MobjInside); + break; + // special functions - manipulation + case polyobj_moveXY: + lua_pushcfunction(L, lib_polyobj_moveXY); + break; + case polyobj_rotate: + lua_pushcfunction(L, lib_polyobj_rotate); + break; + } + return 1; +} + +static int polyobj_set(lua_State *L) +{ + polyobj_t *polyobj = *((polyobj_t **)luaL_checkudata(L, 1, META_POLYOBJ)); + enum polyobj_e field = luaL_checkoption(L, 2, NULL, polyobj_opt); + + if (!polyobj) + return LUA_ErrInvalid(L, "polyobj_t"); + + if (hud_running) + return luaL_error(L, "Do not alter polyobj_t in HUD rendering code!"); + + switch (field) + { + default: + return luaL_error(L, LUA_QL("polyobj_t") " field " LUA_QS " cannot be modified.", polyobj_opt[field]); + case polyobj_angle: + return luaL_error(L, LUA_QL("polyobj_t") " field " LUA_QS " should not be set directly. Use the function " LUA_QL("polyobj:rotate(angle)") " instead.", polyobj_opt[field]); + case polyobj_parent: + polyobj->parent = luaL_checkinteger(L, 3); + break; + case polyobj_flags: + polyobj->flags = luaL_checkinteger(L, 3); + break; + case polyobj_translucency: + polyobj->translucency = luaL_checkinteger(L, 3); + break; + } + + return 0; +} + +static int polyobj_num(lua_State *L) +{ + polyobj_t *polyobj = *((polyobj_t **)luaL_checkudata(L, 1, META_POLYOBJ)); + if (!polyobj) + return luaL_error(L, "accessed polyobj_t doesn't exist anymore."); + lua_pushinteger(L, polyobj-PolyObjects); + return 1; +} + +/////////////////// +// PolyObjects[] // +/////////////////// + +static int lib_iteratePolyObjects(lua_State *L) +{ + INT32 i = -1; + if (lua_gettop(L) < 2) + { + //return luaL_error(L, "Don't call PolyObjects.iterate() directly, use it as 'for polyobj in PolyObjects.iterate do end'."); + lua_pushcfunction(L, lib_iteratePolyObjects); + return 1; + } + lua_settop(L, 2); + lua_remove(L, 1); // state is unused. + if (!lua_isnil(L, 1)) + i = (INT32)(*((polyobj_t **)luaL_checkudata(L, 1, META_POLYOBJ)) - PolyObjects); + for (i++; i < numPolyObjects; i++) + { + LUA_PushUserdata(L, &PolyObjects[i], META_POLYOBJ); + return 1; + } + return 0; +} + +static int lib_PolyObject_getfornum(lua_State *L) +{ + INT32 id = (INT32)luaL_checkinteger(L, 1); + + if (!numPolyObjects) + return 0; // if there's no PolyObjects then bail out here + + LUA_PushUserdata(L, Polyobj_GetForNum(id), META_POLYOBJ); + return 1; +} + +static int lib_getPolyObject(lua_State *L) +{ + const char *field; + INT32 i; + + // find PolyObject by number + if (lua_type(L, 2) == LUA_TNUMBER) + { + i = luaL_checkinteger(L, 2); + if (i < 0 || i >= numPolyObjects) + return luaL_error(L, "PolyObjects[] index %d out of range (0 - %d)", i, numPolyObjects-1); + LUA_PushUserdata(L, &PolyObjects[i], META_POLYOBJ); + return 1; + } + + field = luaL_checkstring(L, 2); + // special function iterate + if (fastcmp(field,"iterate")) + { + lua_pushcfunction(L, lib_iteratePolyObjects); + return 1; + } + // find PolyObject by ID + else if (fastcmp(field,"GetForNum")) // name could probably be better + { + lua_pushcfunction(L, lib_PolyObject_getfornum); + return 1; + } + return 0; +} + +static int lib_numPolyObjects(lua_State *L) +{ + lua_pushinteger(L, numPolyObjects); + return 1; +} + +int LUA_PolyObjLib(lua_State *L) +{ + luaL_newmetatable(L, META_POLYOBJVERTICES); + lua_pushcfunction(L, polyobjvertices_get); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, polyobjvertices_num); + lua_setfield(L, -2, "__len"); + lua_pop(L, 1); + + luaL_newmetatable(L, META_POLYOBJLINES); + lua_pushcfunction(L, polyobjlines_get); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, polyobjlines_num); + lua_setfield(L, -2, "__len"); + lua_pop(L, 1); + + luaL_newmetatable(L, META_POLYOBJ); + lua_pushcfunction(L, polyobj_get); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, polyobj_set); + lua_setfield(L, -2, "__newindex"); + + lua_pushcfunction(L, polyobj_num); + lua_setfield(L, -2, "__len"); + lua_pop(L,1); + + lua_newuserdata(L, 0); + lua_createtable(L, 0, 2); + lua_pushcfunction(L, lib_getPolyObject); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, lib_numPolyObjects); + lua_setfield(L, -2, "__len"); + lua_setmetatable(L, -2); + lua_setglobal(L, "PolyObjects"); + return 0; +} diff --git a/src/lua_script.c b/src/lua_script.c index 0260f018a..ae7f479f6 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -24,6 +24,7 @@ #include "p_saveg.h" #include "p_local.h" #include "p_slopes.h" // for P_SlopeById +#include "p_polyobj.h" // polyobj_t, PolyObjects #ifdef LUA_ALLOW_BYTECODE #include "d_netfil.h" // for LUA_DumpFile #endif @@ -50,6 +51,7 @@ static lua_CFunction liblist[] = { LUA_SkinLib, // skin_t, skins[] LUA_ThinkerLib, // thinker_t LUA_MapLib, // line_t, side_t, sector_t, subsector_t + LUA_PolyObjLib, // polyobj_t LUA_BlockmapLib, // blockmap stuff LUA_HudLib, // HUD stuff NULL @@ -774,6 +776,12 @@ void LUA_InvalidateLevel(void) LUA_InvalidateUserdata(&sides[i]); for (i = 0; i < numvertexes; i++) LUA_InvalidateUserdata(&vertexes[i]); + for (i = 0; i < (size_t)numPolyObjects; i++) + { + LUA_InvalidateUserdata(&PolyObjects[i]); + LUA_InvalidateUserdata(&PolyObjects[i].vertices); + LUA_InvalidateUserdata(&PolyObjects[i].lines); + } #ifdef HAVE_LUA_SEGS for (i = 0; i < numsegs; i++) LUA_InvalidateUserdata(&segs[i]); @@ -832,6 +840,7 @@ enum ARCH_NODE, #endif ARCH_FFLOOR, + ARCH_POLYOBJ, ARCH_SLOPE, ARCH_MAPHEADER, ARCH_SKINCOLOR, @@ -858,6 +867,7 @@ static const struct { {META_NODE, ARCH_NODE}, #endif {META_FFLOOR, ARCH_FFLOOR}, + {META_POLYOBJ, ARCH_POLYOBJ}, {META_SLOPE, ARCH_SLOPE}, {META_MAPHEADER, ARCH_MAPHEADER}, {META_SKINCOLOR, ARCH_SKINCOLOR}, @@ -1126,6 +1136,17 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) } break; } + case ARCH_POLYOBJ: + { + polyobj_t *polyobj = *((polyobj_t **)lua_touserdata(gL, myindex)); + if (!polyobj) + WRITEUINT8(save_p, ARCH_NULL); + else { + WRITEUINT8(save_p, ARCH_POLYOBJ); + WRITEUINT16(save_p, polyobj-PolyObjects); + } + break; + } case ARCH_SLOPE: { pslope_t *slope = *((pslope_t **)lua_touserdata(gL, myindex)); @@ -1381,6 +1402,9 @@ static UINT8 UnArchiveValue(int TABLESINDEX) LUA_PushUserdata(gL, rover, META_FFLOOR); break; } + case ARCH_POLYOBJ: + LUA_PushUserdata(gL, &PolyObjects[READUINT16(save_p)], META_POLYOBJ); + break; case ARCH_SLOPE: LUA_PushUserdata(gL, P_SlopeById(READUINT16(save_p)), META_SLOPE); break; diff --git a/src/m_anigif.c b/src/m_anigif.c index f30effb9b..85118790b 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -507,7 +507,7 @@ static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr) size_t src = 0, dest = 0; size_t size = (vid.width * vid.height * 3); - InitColorLUT(&gif_colorlookup, gif_framepalette, true); + InitColorLUT(&gif_colorlookup, (gif_localcolortable) ? gif_framepalette : gif_headerpalette, true); while (src < size) { diff --git a/src/mserv.c b/src/mserv.c index fa646b899..dfb417415 100644 --- a/src/mserv.c +++ b/src/mserv.c @@ -62,7 +62,7 @@ static CV_PossibleValue_t masterserver_update_rate_cons_t[] = { }; consvar_t cv_masterserver = CVAR_INIT ("masterserver", "https://mb.srb2.org/MS/0", CV_SAVE|CV_CALL, NULL, MasterServer_OnChange); -consvar_t cv_servername = CVAR_INIT ("servername", "SRB2 server", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Update_parameters); +consvar_t cv_servername = CVAR_INIT ("servername", "SRB2 server", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, NULL, Update_parameters); consvar_t cv_masterserver_update_rate = CVAR_INIT ("masterserver_update_rate", "15", CV_SAVE|CV_CALL|CV_NOINIT, masterserver_update_rate_cons_t, Update_parameters); diff --git a/src/p_local.h b/src/p_local.h index cf3a66e9d..8a5084962 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -428,6 +428,7 @@ void P_Initsecnode(void); void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist, UINT8 damagetype, boolean sightcheck); fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height); +fixed_t P_CeilingzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height); boolean PIT_PushableMoved(mobj_t *thing); boolean P_DoSpring(mobj_t *spring, mobj_t *object); diff --git a/src/p_map.c b/src/p_map.c index 74c2790f7..cb06f7d77 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -4963,7 +4963,7 @@ void P_MapEnd(void) } // P_FloorzAtPos -// Returns the floorz of the XYZ position // TODO: Need ceilingpos function too +// Returns the floorz of the XYZ position // Tails 05-26-2003 fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height) { @@ -5007,3 +5007,47 @@ fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height) return floorz; } + +// P_CeilingZAtPos +// Returns the ceilingz of the XYZ position +fixed_t P_CeilingzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height) +{ + sector_t *sec = R_PointInSubsector(x, y)->sector; + fixed_t ceilingz = P_GetSectorCeilingZAt(sec, x, y); + + if (sec->ffloors) + { + ffloor_t *rover; + fixed_t delta1, delta2, thingtop = z + height; + + for (rover = sec->ffloors; rover; rover = rover->next) + { + fixed_t topheight, bottomheight; + if (!(rover->flags & FF_EXISTS)) + continue; + + if ((!(rover->flags & FF_SOLID || rover->flags & FF_QUICKSAND) || (rover->flags & FF_SWIMMABLE))) + continue; + + topheight = P_GetFFloorTopZAt (rover, x, y); + bottomheight = P_GetFFloorBottomZAt(rover, x, y); + + if (rover->flags & FF_QUICKSAND) + { + if (thingtop > bottomheight && topheight > z) + { + if (ceilingz > z) + ceilingz = z; + } + continue; + } + + delta1 = z - (bottomheight + ((topheight - bottomheight)/2)); + delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2)); + if (bottomheight < ceilingz && abs(delta1) > abs(delta2)) + ceilingz = bottomheight; + } + } + + return ceilingz; +} \ No newline at end of file diff --git a/src/p_mobj.c b/src/p_mobj.c index de4385fa7..414d0435c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11047,10 +11047,10 @@ void P_RemoveSavegameMobj(mobj_t *mobj) } static CV_PossibleValue_t respawnitemtime_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}}; -consvar_t cv_itemrespawntime = CVAR_INIT ("respawnitemtime", "30", CV_NETVAR|CV_CHEAT, respawnitemtime_cons_t, NULL); -consvar_t cv_itemrespawn = CVAR_INIT ("respawnitem", "On", CV_NETVAR, CV_OnOff, NULL); +consvar_t cv_itemrespawntime = CVAR_INIT ("respawnitemtime", "30", CV_SAVE|CV_NETVAR|CV_CHEAT, respawnitemtime_cons_t, NULL); +consvar_t cv_itemrespawn = CVAR_INIT ("respawnitem", "On", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); static CV_PossibleValue_t flagtime_cons_t[] = {{0, "MIN"}, {300, "MAX"}, {0, NULL}}; -consvar_t cv_flagtime = CVAR_INIT ("flagtime", "30", CV_NETVAR|CV_CHEAT, flagtime_cons_t, NULL); +consvar_t cv_flagtime = CVAR_INIT ("flagtime", "30", CV_SAVE|CV_NETVAR|CV_CHEAT, flagtime_cons_t, NULL); void P_SpawnPrecipitation(void) { @@ -11956,9 +11956,6 @@ static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i) return MT_SCORE1K_BOX; // 1,000 } - if (mariomode && i == MT_ROSY) - return MT_TOAD; // don't remove on penalty of death - return i; } diff --git a/src/p_polyobj.c b/src/p_polyobj.c index b0a794ddf..63d062c22 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -976,7 +976,7 @@ static INT32 Polyobj_clipThings(polyobj_t *po, line_t *line) // Moves a polyobject on the x-y plane. -static boolean Polyobj_moveXY(polyobj_t *po, fixed_t x, fixed_t y, boolean checkmobjs) +boolean Polyobj_moveXY(polyobj_t *po, fixed_t x, fixed_t y, boolean checkmobjs) { size_t i; vertex_t vec; @@ -1162,7 +1162,7 @@ static void Polyobj_rotateThings(polyobj_t *po, vector2_t origin, angle_t delta, } // Rotates a polyobject around its start point. -static boolean Polyobj_rotate(polyobj_t *po, angle_t delta, UINT8 turnthings, boolean checkmobjs) +boolean Polyobj_rotate(polyobj_t *po, angle_t delta, UINT8 turnthings, boolean checkmobjs) { size_t i; angle_t angle; diff --git a/src/p_polyobj.h b/src/p_polyobj.h index f24caca4e..8c2946965 100644 --- a/src/p_polyobj.h +++ b/src/p_polyobj.h @@ -336,6 +336,8 @@ typedef struct polyfadedata_s // Functions // +boolean Polyobj_moveXY(polyobj_t *po, fixed_t x, fixed_t y, boolean checkmobjs); +boolean Polyobj_rotate(polyobj_t *po, angle_t delta, UINT8 turnthings, boolean checkmobjs); polyobj_t *Polyobj_GetForNum(INT32 id); void Polyobj_InitLevel(void); void Polyobj_MoveOnLoad(polyobj_t *po, angle_t angle, fixed_t x, fixed_t y); diff --git a/src/p_setup.c b/src/p_setup.c index 996e9ec30..7747f6462 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4011,23 +4011,23 @@ boolean P_LoadLevel(boolean fromnetsave) wipegamestate = FORCEWIPEOFF; wipestyleflags = 0; - // Special stage fade to white + // Special stage & record attack retry fade to white // This is handled BEFORE sounds are stopped. - if (modeattacking && !demoplayback && (pausedelay == INT32_MIN)) - ranspecialwipe = 2; + if (G_GetModeAttackRetryFlag()) + { + if (modeattacking && !demoplayback) + { + ranspecialwipe = 2; + wipestyleflags |= (WSF_FADEOUT|WSF_TOWHITE); + } + G_ClearModeAttackRetryFlag(); + } else if (rendermode != render_none && G_IsSpecialStage(gamemap)) { P_RunSpecialStageWipe(); ranspecialwipe = 1; } - if (G_GetModeAttackRetryFlag()) - { - if (modeattacking) - wipestyleflags |= (WSF_FADEOUT|WSF_TOWHITE); - G_ClearModeAttackRetryFlag(); - } - // Make sure all sounds are stopped before Z_FreeTags. S_StopSounds(); S_ClearSfx(); @@ -4187,9 +4187,9 @@ boolean P_LoadLevel(boolean fromnetsave) nextmapoverride = 0; skipstats = 0; - if (!(netgame || multiplayer) && (!modifiedgame || savemoddata)) + if (!(netgame || multiplayer || demoplayback) && (!modifiedgame || savemoddata)) mapvisited[gamemap-1] |= MV_VISITED; - else + else if (netgame || multiplayer) mapvisited[gamemap-1] |= MV_MP; // you want to record that you've been there this session, but not permanently levelloading = false; diff --git a/src/p_user.c b/src/p_user.c index 7bc45bfc4..dda682b6d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -5006,6 +5006,118 @@ static void P_DoTwinSpin(player_t *player) P_SetPlayerMobjState(player->mo, S_PLAY_TWINSPIN); } +// +// returns true if the player used a shield ability, false otherwise +// passing in the mobjs from P_DoJumpStuff is a bit hackily specific, but I don't care enough to make a more elaborate solution (I think that is more appropriately approached with a more general MT_LOCKON spawning system) +// +static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lockonthok, mobj_t *visual) +{ + mobj_t *lockonshield = NULL; + + if ((player->powers[pw_shield] & SH_NOSTACK) && !player->powers[pw_super] && !(player->pflags & PF_SPINDOWN) + && ((!(player->pflags & PF_THOKKED) || (((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP || (player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT) && player->secondjump == UINT8_MAX) ))) // thokked is optional if you're bubblewrapped / 3dblasted + { + if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT) + { + if ((lockonshield = P_LookForEnemies(player, false, false))) + { + if (P_IsLocalPlayer(player)) // Only display it on your own view. + { + boolean dovis = true; + if (lockonshield == lockonthok) + { + if (leveltime & 2) + dovis = false; + else if (visual) + P_RemoveMobj(visual); + } + if (dovis) + { + visual = P_SpawnMobj(lockonshield->x, lockonshield->y, lockonshield->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker + P_SetTarget(&visual->target, lockonshield); + P_SetMobjStateNF(visual, visual->info->spawnstate+1); + } + } + } + } + if (cmd->buttons & BT_SPIN && !LUAh_ShieldSpecial(player)) // Spin button effects + { + // Force stop + if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE) + { + player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + player->mo->momx = player->mo->momy = player->mo->momz = 0; + S_StartSound(player->mo, sfx_ngskid); + } + else + { + switch (player->powers[pw_shield] & SH_NOSTACK) + { + // Whirlwind jump/Thunder jump + case SH_WHIRLWIND: + case SH_THUNDERCOIN: + P_DoJumpShield(player); + break; + // Armageddon pow + case SH_ARMAGEDDON: + player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + P_BlackOw(player); + break; + // Attraction blast + case SH_ATTRACT: + player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + player->homing = 2; + P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockonshield)); + if (lockonshield) + { + player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockonshield->x, lockonshield->y); + player->pflags &= ~PF_NOJUMPDAMAGE; + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); + S_StartSound(player->mo, sfx_s3k40); + player->homing = 3*TICRATE; + } + else + S_StartSound(player->mo, sfx_s3ka6); + break; + // Elemental stomp/Bubble bounce + case SH_ELEMENTAL: + case SH_BUBBLEWRAP: + { + boolean elem = ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL); + player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + if (elem) + { + player->mo->momx = player->mo->momy = 0; + S_StartSound(player->mo, sfx_s3k43); + } + else + { + player->mo->momx -= (player->mo->momx/3); + player->mo->momy -= (player->mo->momy/3); + player->pflags &= ~PF_NOJUMPDAMAGE; + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); + S_StartSound(player->mo, sfx_s3k44); + } + player->secondjump = 0; + P_SetObjectMomZ(player->mo, -24*FRACUNIT, false); + break; + } + // Flame burst + case SH_FLAMEAURA: + player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + P_Thrust(player->mo, player->mo->angle, FixedMul(30*FRACUNIT - FixedSqrt(FixedDiv(player->speed, player->mo->scale)), player->mo->scale)); + player->drawangle = player->mo->angle; + S_StartSound(player->mo, sfx_s3k43); + default: + break; + } + } + } + return player->pflags & PF_SHIELDABILITY; + } + return false; +} + // // P_DoJumpStuff // @@ -5013,7 +5125,7 @@ static void P_DoTwinSpin(player_t *player) // static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) { - mobj_t *lockonthok = NULL, *lockonshield = NULL, *visual = NULL; + mobj_t *lockonthok = NULL, *visual = NULL; if (player->pflags & PF_JUMPSTASIS) return; @@ -5040,107 +5152,8 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) ; else if (player->pflags & (PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player has used an ability previously ; - else if ((player->powers[pw_shield] & SH_NOSTACK) && !player->powers[pw_super] && !(player->pflags & PF_SPINDOWN) - && ((!(player->pflags & PF_THOKKED) || (((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP || (player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT) && player->secondjump == UINT8_MAX) ))) // thokked is optional if you're bubblewrapped / 3dblasted - { - if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT) - { - if ((lockonshield = P_LookForEnemies(player, false, false))) - { - if (P_IsLocalPlayer(player)) // Only display it on your own view. - { - boolean dovis = true; - if (lockonshield == lockonthok) - { - if (leveltime & 2) - dovis = false; - else if (visual) - P_RemoveMobj(visual); - } - if (dovis) - { - visual = P_SpawnMobj(lockonshield->x, lockonshield->y, lockonshield->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker - P_SetTarget(&visual->target, lockonshield); - P_SetMobjStateNF(visual, visual->info->spawnstate+1); - } - } - } - } - if (cmd->buttons & BT_SPIN && !LUAh_ShieldSpecial(player)) // Spin button effects - { - // Force stop - if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE) - { - player->pflags |= PF_THOKKED|PF_SHIELDABILITY; - player->mo->momx = player->mo->momy = player->mo->momz = 0; - S_StartSound(player->mo, sfx_ngskid); - } - else - { - switch (player->powers[pw_shield] & SH_NOSTACK) - { - // Whirlwind jump/Thunder jump - case SH_WHIRLWIND: - case SH_THUNDERCOIN: - P_DoJumpShield(player); - break; - // Armageddon pow - case SH_ARMAGEDDON: - player->pflags |= PF_THOKKED|PF_SHIELDABILITY; - P_BlackOw(player); - break; - // Attraction blast - case SH_ATTRACT: - player->pflags |= PF_THOKKED|PF_SHIELDABILITY; - player->homing = 2; - player->secondjump = 0; - P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockonshield)); - if (lockonshield) - { - player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockonshield->x, lockonshield->y); - player->pflags &= ~PF_NOJUMPDAMAGE; - P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - S_StartSound(player->mo, sfx_s3k40); - player->homing = 3*TICRATE; - } - else - S_StartSound(player->mo, sfx_s3ka6); - break; - // Elemental stomp/Bubble bounce - case SH_ELEMENTAL: - case SH_BUBBLEWRAP: - { - boolean elem = ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL); - player->pflags |= PF_THOKKED|PF_SHIELDABILITY; - if (elem) - { - player->mo->momx = player->mo->momy = 0; - S_StartSound(player->mo, sfx_s3k43); - } - else - { - player->mo->momx -= (player->mo->momx/3); - player->mo->momy -= (player->mo->momy/3); - player->pflags &= ~PF_NOJUMPDAMAGE; - P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - S_StartSound(player->mo, sfx_s3k44); - } - player->secondjump = 0; - P_SetObjectMomZ(player->mo, -24*FRACUNIT, false); - break; - } - // Flame burst - case SH_FLAMEAURA: - player->pflags |= PF_THOKKED|PF_SHIELDABILITY; - P_Thrust(player->mo, player->mo->angle, FixedMul(30*FRACUNIT - FixedSqrt(FixedDiv(player->speed, player->mo->scale)), player->mo->scale)); - player->drawangle = player->mo->angle; - S_StartSound(player->mo, sfx_s3k43); - default: - break; - } - } - } - } + else if (P_PlayerShieldThink(player, cmd, lockonthok, visual)) + ; else if ((cmd->buttons & BT_SPIN)) { if (!(player->pflags & PF_SPINDOWN) && P_SuperReady(player)) diff --git a/src/r_main.c b/src/r_main.c index 9613e2ac1..0c13e3423 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -151,6 +151,7 @@ consvar_t cv_flipcam2 = CVAR_INIT ("flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT, consvar_t cv_shadow = CVAR_INIT ("shadow", "On", CV_SAVE, CV_OnOff, NULL); consvar_t cv_skybox = CVAR_INIT ("skybox", "On", CV_SAVE, CV_OnOff, NULL); +consvar_t cv_ffloorclip = CVAR_INIT ("ffloorclip", "On", CV_SAVE, CV_OnOff, NULL); consvar_t cv_allowmlook = CVAR_INIT ("allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL); consvar_t cv_showhud = CVAR_INIT ("showhud", "Yes", CV_CALL, CV_YesNo, R_SetViewSize); consvar_t cv_translucenthud = CVAR_INIT ("translucenthud", "10", CV_SAVE, translucenthud_cons_t, NULL); @@ -1615,6 +1616,7 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_shadow); CV_RegisterVar(&cv_skybox); + CV_RegisterVar(&cv_ffloorclip); CV_RegisterVar(&cv_cam_dist); CV_RegisterVar(&cv_cam_still); diff --git a/src/r_main.h b/src/r_main.h index 89b359c55..5466d2a25 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -107,6 +107,7 @@ extern consvar_t cv_chasecam, cv_chasecam2; extern consvar_t cv_flipcam, cv_flipcam2; extern consvar_t cv_shadow; +extern consvar_t cv_ffloorclip; extern consvar_t cv_translucency; extern consvar_t cv_drawdist, cv_drawdist_nights, cv_drawdist_precip; extern consvar_t cv_fov; diff --git a/src/r_segs.c b/src/r_segs.c index d9fc75838..2cd7ebab2 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -55,6 +55,15 @@ static INT32 worldtop, worldbottom, worldhigh, worldlow; static INT32 worldtopslope, worldbottomslope, worldhighslope, worldlowslope; // worldtop/bottom at end of slope static fixed_t rw_toptextureslide, rw_midtextureslide, rw_bottomtextureslide; // Defines how to adjust Y offsets along the wall for slopes static fixed_t rw_midtextureback, rw_midtexturebackslide; // Values for masked midtexture height calculation + +// Lactozilla: 3D floor clipping +static boolean rw_floormarked = false; +static boolean rw_ceilingmarked = false; + +static INT32 *rw_silhouette = NULL; +static fixed_t *rw_tsilheight = NULL; +static fixed_t *rw_bsilheight = NULL; + static fixed_t pixhigh, pixlow, pixhighstep, pixlowstep; static fixed_t topfrac, topstep; static fixed_t bottomfrac, bottomstep; @@ -686,6 +695,19 @@ static void R_DrawRepeatFlippedMaskedColumn(column_t *col) } while (sprtopscreen < sprbotscreen); } +// Returns true if a fake floor is translucent. +static boolean R_IsFFloorTranslucent(visffloor_t *pfloor) +{ + if (pfloor->polyobj) + return (pfloor->polyobj->translucency > 0); + + // Polyobjects have no ffloors, and they're handled in the conditional above. + if (pfloor->ffloor != NULL) + return (pfloor->ffloor->flags & FF_TRANSLUCENT); + + return false; +} + // // R_RenderThickSideRange // Renders all the thick sides in the given range. @@ -1188,7 +1210,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) // R_ExpandPlaneY // -// A simple function to modify a vsplane's top and bottom for a particular column +// A simple function to modify a visplane's top and bottom for a particular column // Sort of like R_ExpandPlane in r_plane.c, except this is vertical expansion static inline void R_ExpandPlaneY(visplane_t *pl, INT32 x, INT16 top, INT16 bottom) { @@ -1198,6 +1220,14 @@ static inline void R_ExpandPlaneY(visplane_t *pl, INT32 x, INT16 top, INT16 bott if (pl->bottom[x] < bottom) pl->bottom[x] = bottom; } +// R_FFloorCanClip +// +// Returns true if a fake floor can clip a column away. +static boolean R_FFloorCanClip(visffloor_t *pfloor) +{ + return (cv_ffloorclip.value && !R_IsFFloorTranslucent(pfloor) && !pfloor->polyobj); +} + // // R_RenderSegLoop // Draws zero, one, or two textures (and possibly a masked @@ -1279,8 +1309,13 @@ static void R_RenderSegLoop (void) R_ExpandPlaneY(floorplane, rw_x, top, bottom); } + rw_floormarked = false; + rw_ceilingmarked = false; + if (numffloors) { + INT16 fftop, ffbottom; + firstseg->frontscale[rw_x] = frontscale[rw_x]; top = ceilingclip[rw_x]+1; // PRBoom bottom = floorclip[rw_x]-1; // PRBoom @@ -1311,8 +1346,30 @@ static void R_RenderSegLoop (void) { if (top_w <= bottom_w) { - ffloor[i].plane->top[rw_x] = (INT16)top_w; - ffloor[i].plane->bottom[rw_x] = (INT16)bottom_w; + fftop = (INT16)top_w; + ffbottom = (INT16)bottom_w; + + ffloor[i].plane->top[rw_x] = fftop; + ffloor[i].plane->bottom[rw_x] = ffbottom; + + // Lactozilla: Cull part of the column by the 3D floor if it can't be seen + // "bottom" is the top pixel of the floor column + if (ffbottom >= bottom-1 && R_FFloorCanClip(&ffloor[i])) + { + rw_floormarked = true; + floorclip[rw_x] = fftop; + if (yh > fftop) + yh = fftop; + + if (markfloor && floorplane) + floorplane->top[rw_x] = bottom; + + if (rw_silhouette) + { + (*rw_silhouette) |= SIL_BOTTOM; + (*rw_bsilheight) = INT32_MAX; + } + } } } } @@ -1337,8 +1394,30 @@ static void R_RenderSegLoop (void) { if (top_w <= bottom_w) { - ffloor[i].plane->top[rw_x] = (INT16)top_w; - ffloor[i].plane->bottom[rw_x] = (INT16)bottom_w; + fftop = (INT16)top_w; + ffbottom = (INT16)bottom_w; + + ffloor[i].plane->top[rw_x] = fftop; + ffloor[i].plane->bottom[rw_x] = ffbottom; + + // Lactozilla: Cull part of the column by the 3D floor if it can't be seen + // "top" is the height of the ceiling column + if (fftop <= top+1 && R_FFloorCanClip(&ffloor[i])) + { + rw_ceilingmarked = true; + ceilingclip[rw_x] = ffbottom; + if (yl < ffbottom) + yl = ffbottom; + + if (markceiling && ceilingplane) + ceilingplane->bottom[rw_x] = top; + + if (rw_silhouette) + { + (*rw_silhouette) |= SIL_TOP; + (*rw_tsilheight) = INT32_MIN; + } + } } } } @@ -1444,20 +1523,25 @@ static void R_RenderSegLoop (void) // dont draw anything more for this column, since // a midtexture blocks the view - ceilingclip[rw_x] = (INT16)viewheight; - floorclip[rw_x] = -1; + if (!rw_ceilingmarked) + ceilingclip[rw_x] = (INT16)viewheight; + if (!rw_floormarked) + floorclip[rw_x] = -1; } else { // note: don't use min/max macros, since casting from INT32 to INT16 is involved here - if (markceiling) + if (markceiling && (!rw_ceilingmarked)) ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1; - if (markfloor) + if (markfloor && (!rw_floormarked)) floorclip[rw_x] = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight; } } else { + INT16 topclip = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1; + INT16 bottomclip = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight; + // two sided line if (toptexture) { @@ -1471,7 +1555,10 @@ static void R_RenderSegLoop (void) if (mid >= yl) // back ceiling lower than front ceiling ? { if (yl >= viewheight) // entirely off bottom of screen - ceilingclip[rw_x] = (INT16)viewheight; + { + if (!rw_ceilingmarked) + ceilingclip[rw_x] = (INT16)viewheight; + } else if (mid >= 0) // safe to draw top texture { dc_yl = yl; @@ -1482,14 +1569,14 @@ static void R_RenderSegLoop (void) colfunc(); ceilingclip[rw_x] = (INT16)mid; } - else // entirely off top of screen + else if (!rw_ceilingmarked) // entirely off top of screen ceilingclip[rw_x] = -1; } - else - ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1; + else if (!rw_ceilingmarked) + ceilingclip[rw_x] = topclip; } - else if (markceiling) // no top wall - ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1; + else if (markceiling && (!rw_ceilingmarked)) // no top wall + ceilingclip[rw_x] = topclip; if (bottomtexture) { @@ -1504,7 +1591,10 @@ static void R_RenderSegLoop (void) if (mid <= yh) // back floor higher than front floor ? { if (yh < 0) // entirely off top of screen - floorclip[rw_x] = -1; + { + if (!rw_floormarked) + floorclip[rw_x] = -1; + } else if (mid < viewheight) // safe to draw bottom texture { dc_yl = mid; @@ -1516,14 +1606,14 @@ static void R_RenderSegLoop (void) colfunc(); floorclip[rw_x] = (INT16)mid; } - else // entirely off bottom of screen + else if (!rw_floormarked) // entirely off bottom of screen floorclip[rw_x] = (INT16)viewheight; } - else - floorclip[rw_x] = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight; + else if (!rw_floormarked) + floorclip[rw_x] = bottomclip; } - else if (markfloor) // no bottom wall - floorclip[rw_x] = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight; + else if (markfloor && (!rw_floormarked)) // no bottom wall + floorclip[rw_x] = bottomclip; } if (maskedtexture || numthicksides) @@ -2786,6 +2876,10 @@ void R_StoreWallRange(INT32 start, INT32 stop) } } + rw_silhouette = &(ds_p->silhouette); + rw_tsilheight = &(ds_p->tsilheight); + rw_bsilheight = &(ds_p->bsilheight); + #ifdef WALLSPLATS if (linedef->splats && cv_splats.value) { diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index 755fa68e6..5b0ff7425 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -401,6 +401,7 @@ + diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters index 3bbcd9cb5..505384313 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj.filters +++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters @@ -723,6 +723,9 @@ LUA + + LUA + LUA diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index 416c8d2f5..e545bbb63 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -104,14 +104,13 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(MakeScreenFinalTexture); GETFUNC(DrawScreenFinalTexture); - GETFUNC(LoadShaders); - GETFUNC(KillShaders); + GETFUNC(CompileShaders); + GETFUNC(CleanShaders); GETFUNC(SetShader); GETFUNC(UnSetShader); GETFUNC(SetShaderInfo); GETFUNC(LoadCustomShader); - GETFUNC(InitCustomShaders); #else //HWRENDER if (0 == strcmp("FinishUpdate", funcName)) diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 749dab4fa..a49adb508 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1660,7 +1660,7 @@ static void Impl_SetWindowName(const char *title) static void Impl_SetWindowIcon(void) { if (window && icoSurface) - SDL_SetWindowIcon(window, icoSurface); + SDL_SetWindowIcon(window, icoSurface); } static void Impl_VideoSetupSDLBuffer(void) @@ -1770,7 +1770,7 @@ void I_StartupGraphics(void) // Window icon #ifdef HAVE_IMAGE icoSurface = IMG_ReadXPMFromArray(SDL_icon_xpm); -#endif +#endif // Fury: we do window initialization after GL setup to allow // SDL_GL_LoadLibrary to work well on Windows @@ -1855,14 +1855,13 @@ void VID_StartupOpenGL(void) HWD.pfnMakeScreenFinalTexture=hwSym("MakeScreenFinalTexture",NULL); HWD.pfnDrawScreenFinalTexture=hwSym("DrawScreenFinalTexture",NULL); - HWD.pfnLoadShaders = hwSym("LoadShaders",NULL); - HWD.pfnKillShaders = hwSym("KillShaders",NULL); + HWD.pfnCompileShaders = hwSym("CompileShaders",NULL); + HWD.pfnCleanShaders = hwSym("CleanShaders",NULL); HWD.pfnSetShader = hwSym("SetShader",NULL); HWD.pfnUnSetShader = hwSym("UnSetShader",NULL); HWD.pfnSetShaderInfo = hwSym("SetShaderInfo",NULL); HWD.pfnLoadCustomShader = hwSym("LoadCustomShader",NULL); - HWD.pfnInitCustomShaders= hwSym("InitCustomShaders",NULL); vid_opengl_state = HWD.pfnInit() ? 1 : -1; // let load the OpenGL library diff --git a/src/w_wad.c b/src/w_wad.c index 11679b8f4..fd70f8ec3 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -849,8 +849,8 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) // Read shaders from file if (rendermode == render_opengl && (vid_opengl_state == 1)) { - HWR_ReadShaders(numwadfiles - 1, (type == RET_PK3)); - HWR_LoadShaders(); + HWR_LoadCustomShadersFromFile(numwadfiles - 1, (type == RET_PK3)); + HWR_CompileShaders(); } #endif // HWRENDER