From 9446999c4c00c7fb8ce873f5514eda5de6521a67 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 28 Dec 2008 13:27:13 +0000 Subject: [PATCH] - Added Skulltag's HQ resite feature - removed special handling for old ZSBSPs that threw out overlapping linedefs. If such nodes are encountered now a rebuild is forced instead of trying to work with the broken data. - Update to ZDoom r1333: - Added Karate Chris's new DMFlags submission. - Fixed: The correct player class was not remembered when the menu had both a player class selection menu and an episode menu. - Fixed: AddToConsole could write outside its working buffer. - Fixed: 0 was no longer recognized as placeholder for 'no state' in A_Chase. - Fixed: When picking up weapons the code did not check if it should switch away from weak weapons. git-svn-id: http://mancubus.net/svn/hosted/gzdoom/trunk@279 b0f79afe-0144-0410-b225-9a4edf0717df --- docs/rh-log.txt | 11 ++ gzdoom.vcproj | 12 +- src/CMakeLists.txt | 1 - src/am_map.cpp | 8 ++ src/c_cmds.cpp | 3 +- src/c_console.cpp | 11 +- src/d_main.cpp | 65 ++++++++- src/d_netinfo.cpp | 22 ++- src/d_player.h | 6 +- src/doomdef.h | 11 +- src/g_game.cpp | 4 + src/g_shared/a_pickups.cpp | 13 +- src/g_shared/a_specialspot.cpp | 2 +- src/g_shared/a_weapons.cpp | 9 ++ src/gl/gl_bsp.cpp | 2 +- src/gl/gl_data.cpp | 1 - src/gl/gl_drawinfo.cpp | 1 + src/gl/gl_fakeflat.cpp | 1 + src/gl/gl_functions.h | 5 - src/gl/gl_hqresize.cpp | 225 +++++++++++++++++++++++++++++ src/gl/gl_hqresize.h | 43 ++++++ src/gl/gl_menu.cpp | 22 +++ src/gl/gl_missinglines.cpp | 239 ------------------------------- src/gl/gl_missingtexture.cpp | 3 +- src/gl/gl_nodes.cpp | 75 +++++++++- src/gl/gl_renderstruct.h | 2 +- src/gl/gl_scene.cpp | 1 - src/gl/gl_sections.cpp | 2 + src/gl/gl_shader.cpp | 2 +- src/gl/gl_struct.h | 8 +- src/gl/gl_texture.cpp | 6 +- src/gl/gl_walls.cpp | 4 +- src/m_menu.cpp | 9 +- src/m_options.cpp | 8 ++ src/p_interaction.cpp | 4 + src/p_spec.cpp | 4 + src/p_user.cpp | 25 ++++ src/svnrevision.h | 4 +- src/thingdef/thingdef_states.cpp | 9 +- 39 files changed, 583 insertions(+), 300 deletions(-) create mode 100644 src/gl/gl_hqresize.cpp create mode 100644 src/gl/gl_hqresize.h delete mode 100644 src/gl/gl_missinglines.cpp diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 3aaa379d..02a4ff0e 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,14 @@ +December 28, 2008 (Changes by Graf Zahl) +- Added Karate Chris's new DMFlags submission. + +December 27, 2008 (Changes by Graf Zahl) +- Fixed: The correct player class was not remembered when the menu had both + a player class selection menu and an episode menu. +- Fixed: AddToConsole could write outside its working buffer. +- Fixed: 0 was no longer recognized as placeholder for 'no state' in A_Chase. +- Fixed: When picking up weapons the code did not check if it should switch away + from weak weapons. + December 20, 2008 - OggMod improperly decodes the right channel of stereo samples when sending them to OggEnc, so I have no choice but to convert them to mono by chopping diff --git a/gzdoom.vcproj b/gzdoom.vcproj index 7599e4e5..f285653d 100644 --- a/gzdoom.vcproj +++ b/gzdoom.vcproj @@ -6424,6 +6424,10 @@ RelativePath=".\src\gl\gl_hirestex.cpp" > + + @@ -6432,10 +6436,6 @@ RelativePath=".\src\gl\gl_menu.cpp" > - - @@ -6559,6 +6559,10 @@ RelativePath=".\src\gl\gl_include.h" > + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2e213a3d..9f05c91c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -620,7 +620,6 @@ add_executable( zdoom WIN32 gl/gl_hirestex.cpp gl/gl_light.cpp gl/gl_menu.cpp - gl/gl_missinglines.cpp gl/gl_missingtexture.cpp gl/gl_models.cpp gl/gl_models_md2.cpp diff --git a/src/am_map.cpp b/src/am_map.cpp index 29f42b00..36c10d63 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -863,6 +863,10 @@ void AM_ToggleMap () if (gamestate != GS_LEVEL) return; + // Don't activate the automap if we're not allowed to use it. + if (dmflags2 & DF2_NO_AUTOMAP) + return; + SB_state = screen->GetPageCount (); if (!automapactive) { @@ -1572,6 +1576,10 @@ void AM_drawPlayers () { continue; } + + // We don't always want to show allies on the automap. + if (dmflags2 & DF2_NO_AUTOMAP_ALLIES && i != consoleplayer) + continue; if (deathmatch && !demoplayback && !p->mo->IsTeammate (players[consoleplayer].mo) && diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index ca208e47..e4197ce2 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -232,7 +232,8 @@ CCMD (chase) } else { - if (gamestate == GS_LEVEL && deathmatch && CheckCheatmode ()) + // Check if we're allowed to use chasecam. + if (gamestate != GS_LEVEL || (!(dmflags2 & DF2_CHASECAM) && CheckCheatmode ())) return; Net_WriteByte (DEM_GENERICCHEAT); diff --git a/src/c_console.cpp b/src/c_console.cpp index d66c403d..76d13574 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -667,7 +667,7 @@ void AddToConsole (int printlevel, const char *text) } len = (int)strlen (text); - size = len + 3; + size = len + 20; if (addtype != NEWLINE) { @@ -767,6 +767,15 @@ void AddToConsole (int printlevel, const char *text) if (*work_p) { linestart = work_p - 1 - cc.Len(); + if (linestart < work) + { + // The line start is outside the buffer. + // Make space for the newly inserted stuff. + size_t movesize = work-linestart; + memmove(work + movesize, work, strlen(work)); + work_p += movesize; + linestart = work; + } linestart[0] = TEXTCOLOR_ESCAPE; strncpy (linestart + 1, cc, cc.Len()); } diff --git a/src/d_main.cpp b/src/d_main.cpp index 2418e47e..5cf9692d 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -99,6 +99,7 @@ #include "d_event.h" #include "d_netinf.h" #include "v_palette.h" +#include "m_cheat.h" EXTERN_CVAR(Bool, hud_althud) void DrawHUD(); @@ -114,6 +115,7 @@ extern void M_SetDefaultMode (); extern void R_ExecuteSetViewSize (); extern void G_NewInit (); extern void SetupPlayerClasses (); +extern bool CheckCheatmode (); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -139,6 +141,7 @@ EXTERN_CVAR (Float, m_yaw) EXTERN_CVAR (Bool, invertmouse) EXTERN_CVAR (Bool, lookstrafe) EXTERN_CVAR (Int, screenblocks) +EXTERN_CVAR (Bool, sv_cheats) extern gameinfo_t SharewareGameInfo; extern gameinfo_t RegisteredGameInfo; @@ -440,7 +443,58 @@ CVAR (Flag, sv_allowcrouch, dmflags, DF_YES_CROUCH); // //========================================================================== -CVAR (Int, dmflags2, 0, CVAR_SERVERINFO); +CUSTOM_CVAR (Int, dmflags2, 0, CVAR_SERVERINFO) +{ + // Stop the automap if we aren't allowed to use it. + if ((self & DF2_NO_AUTOMAP) && automapactive) + AM_Stop (); + + for (int i = 0; i < MAXPLAYERS; i++) + { + player_t *p = &players[i]; + + if (!playeringame[i]) + continue; + + // Revert our view to our own eyes if spying someone else. + if (self & DF2_DISALLOW_SPYING) + { + // The player isn't looking through its own eyes, so make it. + if (p->camera != p->mo) + { + p->camera = p->mo; + + S_UpdateSounds (p->camera); + StatusBar->AttachToPlayer (p); + + if (demoplayback || multiplayer) + StatusBar->ShowPlayerName (); + } + } + + // Come out of chasecam mode if we're not allowed to use chasecam. + if (!(dmflags2 & DF2_CHASECAM) && !G_SkillProperty (SKILLP_DisableCheats) && !sv_cheats) + { + // Take us out of chasecam mode only. + if (p->cheats & CF_CHASECAM) + cht_DoCheat (p, CHT_CHASECAM); + } + + // Change our autoaim settings if need be. + if (dmflags2 & DF2_NOAUTOAIM) + { + // Save our aimdist and set aimdist to 0. + p->userinfo.savedaimdist = p->userinfo.aimdist; + p->userinfo.aimdist = 0; + } + else + { + // Restore our aimdist. + p->userinfo.aimdist = p->userinfo.savedaimdist; + } + } +} + CVAR (Flag, sv_weapondrop, dmflags2, DF2_YES_WEAPONDROP); CVAR (Flag, sv_noteamswitch, dmflags2, DF2_NO_TEAM_SWITCH); CVAR (Flag, sv_doubleammo, dmflags2, DF2_YES_DOUBLEAMMO); @@ -452,7 +506,14 @@ CVAR (Flag, sv_norespawn, dmflags2, DF2_NO_RESPAWN); CVAR (Flag, sv_losefrag, dmflags2, DF2_YES_LOSEFRAG); CVAR (Flag, sv_respawnprotect, dmflags2, DF2_YES_RESPAWN_INVUL); CVAR (Flag, sv_samespawnspot, dmflags2, DF2_SAME_SPAWN_SPOT); -CVAR (Flag, sv_infiniteinventory, dmflags2, DF2_INFINITE_INVENTORY) +CVAR (Flag, sv_infiniteinventory, dmflags2, DF2_INFINITE_INVENTORY); +CVAR (Flag, sv_killallmonsters, dmflags2, DF2_KILL_MONSTERS); +CVAR (Flag, sv_noautomap, dmflags2, DF2_NO_AUTOMAP); +CVAR (Flag, sv_noautomapallies, dmflags2, DF2_NO_AUTOMAP_ALLIES); +CVAR (Flag, sv_disallowspying, dmflags2, DF2_DISALLOW_SPYING); +CVAR (Flag, sv_chasecam, dmflags2, DF2_CHASECAM); +CVAR (Flag, sv_disallowsuicide, dmflags2, DF2_NOSUICIDE); +CVAR (Flag, sv_noautoaim, dmflags2, DF2_NOAUTOAIM); //========================================================================== // diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 6f22a271..6f5b331c 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -370,11 +370,17 @@ void D_SetupUserInfo () } if (autoaim > 35.f || autoaim < 0.f) { - coninfo->aimdist = ANGLE_1*35; + if (dmflags & DF2_NOAUTOAIM) + coninfo->savedaimdist = ANGLE_1*35; + else + coninfo->aimdist = ANGLE_1*35; } else { - coninfo->aimdist = abs ((int)(autoaim * (float)ANGLE_1)); + if (dmflags & DF2_NOAUTOAIM) + coninfo->savedaimdist = abs ((int)(autoaim * (float)ANGLE_1)); + else + coninfo->aimdist = abs ((int)(autoaim * (float)ANGLE_1)); } coninfo->color = color; coninfo->skin = R_FindSkin (skin, 0); @@ -684,11 +690,17 @@ void D_ReadUserInfoStrings (int i, BYTE **stream, bool update) angles = atof (value); if (angles > 35.f || angles < 0.f) { - info->aimdist = ANGLE_1*35; + if (dmflags & DF2_NOAUTOAIM) + info->savedaimdist = ANGLE_1*35; + else + info->aimdist = ANGLE_1*35; } else { - info->aimdist = abs ((int)(angles * (float)ANGLE_1)); + if (dmflags & DF2_NOAUTOAIM) + info->savedaimdist = abs ((int)(angles * (float)ANGLE_1)); + else + info->aimdist = abs ((int)(angles * (float)ANGLE_1)); } } break; @@ -804,6 +816,8 @@ FArchive &operator<< (FArchive &arc, userinfo_t &info) arc.Read (&info.netname, sizeof(info.netname)); } arc << info.team << info.aimdist << info.color << info.skin << info.gender << info.neverswitch; + if (SaveVersion >= 1333) arc << info.savedaimdist; + else info.savedaimdist = info.aimdist; return arc; } diff --git a/src/d_player.h b/src/d_player.h index 2bc471a3..1d33a99a 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -82,8 +82,9 @@ public: virtual void TweakSpeeds (int &forwardmove, int &sidemove); virtual void MorphPlayerThink (); virtual void ActivateMorphWeapon (); - virtual AWeapon *PickNewWeapon (const PClass *ammotype); - virtual AWeapon *BestWeapon (const PClass *ammotype); + AWeapon *PickNewWeapon (const PClass *ammotype); + AWeapon *BestWeapon (const PClass *ammotype); + void CheckWeaponSwitch(const PClass *ammotype); virtual void GiveDeathmatchInventory (); virtual void FilterCoopRespawnInventory (APlayerPawn *oldplayer); @@ -196,6 +197,7 @@ struct userinfo_t { char netname[MAXPLAYERNAME+1]; BYTE team; + int savedaimdist; int aimdist; int color; int skin; diff --git a/src/doomdef.h b/src/doomdef.h index 03635193..addad750 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -243,12 +243,17 @@ enum DF2_YES_RESPAWN_INVUL = 1 << 10, // Player is temporarily invulnerable when respawned // DF2_COOP_SHOTGUNSTART = 1 << 11, // All playres start with a shotgun when they respawn DF2_SAME_SPAWN_SPOT = 1 << 12, // Players respawn in the same place they died (co-op) - DF2_YES_KEEPFRAGS = 1 << 13, // Don't clear frags after each level DF2_NO_RESPAWN = 1 << 14, // Player cannot respawn - DF2_YES_LOSEFRAG = 1 << 15, // Lose a frag when killed. More incentive to try to -// // not get yerself killed + DF2_YES_LOSEFRAG = 1 << 15, // Lose a frag when killed. More incentive to try to not get yerself killed DF2_INFINITE_INVENTORY = 1 << 16, // Infinite inventory. + DF2_KILL_MONSTERS = 1 << 17, // All monsters must be killed before the level exits. + DF2_NO_AUTOMAP = 1 << 18, // Players are allowed to see the automap. + DF2_NO_AUTOMAP_ALLIES = 1 << 19, // Allies can been seen on the automap. + DF2_DISALLOW_SPYING = 1 << 20, // You can spy on your allies. + DF2_CHASECAM = 1 << 21, // Players can use the chasecam cheat. + DF2_NOSUICIDE = 1 << 22, // Players are allowed to suicide. + DF2_NOAUTOAIM = 1 << 23, // Players cannot use autoaim. }; // [RH] Compatibility flags. diff --git a/src/g_game.cpp b/src/g_game.cpp index 494a2fd2..7ca1b242 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -724,6 +724,10 @@ static void ChangeSpy (bool forward) return; } + // We may not be allowed to spy on anyone. + if (dmflags2 & DF2_DISALLOW_SPYING) + return; + // Otherwise, cycle to the next player. bool checkTeam = !demoplayback && deathmatch; int pnum = players[consoleplayer].camera->player - players; diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index e3309fc8..8ae26365 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -96,18 +96,9 @@ bool AAmmo::HandlePickup (AInventory *item) assert (Owner != NULL); - if (oldamount == 0 && Owner != NULL && Owner->player != NULL && - !Owner->player->userinfo.neverswitch && - Owner->player->PendingWeapon == WP_NOCHANGE && - (Owner->player->ReadyWeapon == NULL || - (Owner->player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))) + if (oldamount == 0 && Owner != NULL && Owner->player != NULL) { - AWeapon *best = barrier_cast(Owner)->BestWeapon (GetClass()); - if (best != NULL && (Owner->player->ReadyWeapon == NULL || - best->SelectionOrder < Owner->player->ReadyWeapon->SelectionOrder)) - { - Owner->player->PendingWeapon = best; - } + barrier_cast(Owner)->CheckWeaponSwitch(GetClass()); } } return true; diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index 5064b048..dbf2cffc 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -129,7 +129,7 @@ struct FSpotList ASpecialSpot *GetNextInList(int skipcounter) { - if (++SkipCount > skipcounter) + if (Spots.Size() > 0 && ++SkipCount > skipcounter) { SkipCount = 0; diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index 33f27930..b74a4e20 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -158,8 +158,17 @@ bool AWeapon::PickupForAmmo (AWeapon *ownedWeapon) // Don't take ammo if the weapon sticks around. if (!ShouldStay ()) { + int oldamount = 0; + if (ownedWeapon->Ammo1 != NULL) oldamount = ownedWeapon->Ammo1->Amount; + if (AmmoGive1 > 0) gotstuff = AddExistingAmmo (ownedWeapon->Ammo1, AmmoGive1); if (AmmoGive2 > 0) gotstuff |= AddExistingAmmo (ownedWeapon->Ammo2, AmmoGive2); + + AActor *Owner = ownedWeapon->Owner; + if (gotstuff && oldamount == 0 && Owner != NULL && Owner->player != NULL) + { + static_cast(Owner)->CheckWeaponSwitch(ownedWeapon->Ammo1->GetClass()); + } } return gotstuff; } diff --git a/src/gl/gl_bsp.cpp b/src/gl/gl_bsp.cpp index c9d671c8..6b991a04 100644 --- a/src/gl/gl_bsp.cpp +++ b/src/gl/gl_bsp.cpp @@ -151,7 +151,7 @@ static void AddLine (seg_t *seg,sector_t * sector,subsector_t * polysub) SetupWall.Clock(); - wall.Process(seg, sector, backsector, polysub); + wall.Process(seg, sector, backsector, polysub, gl_render_segs); rendered_lines++; SetupWall.Unclock(); diff --git a/src/gl/gl_data.cpp b/src/gl/gl_data.cpp index 88feb54f..a2ca82f2 100644 --- a/src/gl/gl_data.cpp +++ b/src/gl/gl_data.cpp @@ -727,7 +727,6 @@ void gl_PreprocessLevel() vt->vt = vtx; } } - gl_CollectMissingLines(); gl_InitVertexData(); gl_CreateSections(); diff --git a/src/gl/gl_drawinfo.cpp b/src/gl/gl_drawinfo.cpp index f58c574a..ecc2e61c 100644 --- a/src/gl/gl_drawinfo.cpp +++ b/src/gl/gl_drawinfo.cpp @@ -806,6 +806,7 @@ static int __cdecl dicmp (const void *a, const void *b) case GLDIT_POLY: break; } } + if (lights[0]!=lights[1]) return lights[0]-lights[1]; if (tx[0]!=tx[1]) return tx[0]-tx[1]; /*if (lights[0]!=lights[1])*/ return lights[0]-lights[1]; } diff --git a/src/gl/gl_fakeflat.cpp b/src/gl/gl_fakeflat.cpp index de813dbd..17e30bcc 100644 --- a/src/gl/gl_fakeflat.cpp +++ b/src/gl/gl_fakeflat.cpp @@ -254,6 +254,7 @@ sector_t * gl_FakeFlat(sector_t * sec, sector_t * dest, bool back) #endif #endif + area_t in_area = ::in_area; if (in_area==area_above) { diff --git a/src/gl/gl_functions.h b/src/gl/gl_functions.h index b23bd609..8f18ba1d 100644 --- a/src/gl/gl_functions.h +++ b/src/gl/gl_functions.h @@ -131,11 +131,6 @@ angle_t gl_FrustumAngle(); void gl_LinkLights(); -// ZDBSP shittiness compensation -void gl_CollectMissingLines(); -void gl_RenderMissingLines(); - - void gl_SetActorLights(AActor *); void gl_DeleteAllAttachedLights(); void gl_RecreateAllAttachedLights(); diff --git a/src/gl/gl_hqresize.cpp b/src/gl/gl_hqresize.cpp new file mode 100644 index 00000000..072ec2cd --- /dev/null +++ b/src/gl/gl_hqresize.cpp @@ -0,0 +1,225 @@ +/* +** gl_hqresize.cpp +** Contains high quality upsampling functions. +** So far Scale2x/3x/4x as described in http://scale2x.sourceforge.net/ +** are implemented. +** +**--------------------------------------------------------------------------- +** Copyright 2008 Benjamin Berkels +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "gl_hqresize.h" +#include "c_cvars.h" + +CUSTOM_CVAR(Int, gl_texture_hqresize, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + if (self < 0 || self > 3) self = 0; + FGLTexture::FlushAll(); +} + +CUSTOM_CVAR(Int, gl_texture_hqresize_maxinputsize, 512, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + if (self > 1024) self = 1024; + FGLTexture::FlushAll(); +} + +CUSTOM_CVAR(Int, gl_texture_hqresize_targets, 7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + FGLTexture::FlushAll(); +} + +CVAR (Flag, gl_texture_hqresize_textures, gl_texture_hqresize_targets, 1); +CVAR (Flag, gl_texture_hqresize_sprites, gl_texture_hqresize_targets, 2); +CVAR (Flag, gl_texture_hqresize_fonts, gl_texture_hqresize_targets, 4); + + +static void scale2x ( uint32* inputBuffer, uint32* outputBuffer, int inWidth, int inHeight ) +{ + const int width = 2* inWidth; + const int height = 2 * inHeight; + + for ( int i = 0; i < inWidth; ++i ) + { + const int iMinus = (i > 0) ? (i-1) : 0; + const int iPlus = (i < inWidth - 1 ) ? (i+1) : i; + for ( int j = 0; j < inHeight; ++j ) + { + const int jMinus = (j > 0) ? (j-1) : 0; + const int jPlus = (j < inHeight - 1 ) ? (j+1) : j; + const uint32 A = inputBuffer[ iMinus +inWidth*jMinus]; + const uint32 B = inputBuffer[ iMinus +inWidth*j ]; + const uint32 C = inputBuffer[ iMinus +inWidth*jPlus]; + const uint32 D = inputBuffer[ i +inWidth*jMinus]; + const uint32 E = inputBuffer[ i +inWidth*j ]; + const uint32 F = inputBuffer[ i +inWidth*jPlus]; + const uint32 G = inputBuffer[ iPlus +inWidth*jMinus]; + const uint32 H = inputBuffer[ iPlus +inWidth*j ]; + const uint32 I = inputBuffer[ iPlus +inWidth*jPlus]; + if (B != H && D != F) { + outputBuffer[2*i + width*2*j ] = D == B ? D : E; + outputBuffer[2*i + width*(2*j+1)] = B == F ? F : E; + outputBuffer[2*i+1 + width*2*j ] = D == H ? D : E; + outputBuffer[2*i+1 + width*(2*j+1)] = H == F ? F : E; + } else { + outputBuffer[2*i + width*2*j ] = E; + outputBuffer[2*i + width*(2*j+1)] = E; + outputBuffer[2*i+1 + width*2*j ] = E; + outputBuffer[2*i+1 + width*(2*j+1)] = E; + } + } + } +} + +static void scale3x ( uint32* inputBuffer, uint32* outputBuffer, int inWidth, int inHeight ) +{ + const int width = 3* inWidth; + const int height = 3 * inHeight; + + for ( int i = 0; i < inWidth; ++i ) + { + const int iMinus = (i > 0) ? (i-1) : 0; + const int iPlus = (i < inWidth - 1 ) ? (i+1) : i; + for ( int j = 0; j < inHeight; ++j ) + { + const int jMinus = (j > 0) ? (j-1) : 0; + const int jPlus = (j < inHeight - 1 ) ? (j+1) : j; + const uint32 A = inputBuffer[ iMinus +inWidth*jMinus]; + const uint32 B = inputBuffer[ iMinus +inWidth*j ]; + const uint32 C = inputBuffer[ iMinus +inWidth*jPlus]; + const uint32 D = inputBuffer[ i +inWidth*jMinus]; + const uint32 E = inputBuffer[ i +inWidth*j ]; + const uint32 F = inputBuffer[ i +inWidth*jPlus]; + const uint32 G = inputBuffer[ iPlus +inWidth*jMinus]; + const uint32 H = inputBuffer[ iPlus +inWidth*j ]; + const uint32 I = inputBuffer[ iPlus +inWidth*jPlus]; + if (B != H && D != F) { + outputBuffer[3*i + width*3*j ] = D == B ? D : E; + outputBuffer[3*i + width*(3*j+1)] = (D == B && E != C) || (B == F && E != A) ? B : E; + outputBuffer[3*i + width*(3*j+2)] = B == F ? F : E; + outputBuffer[3*i+1 + width*3*j ] = (D == B && E != G) || (D == H && E != A) ? D : E; + outputBuffer[3*i+1 + width*(3*j+1)] = E; + outputBuffer[3*i+1 + width*(3*j+2)] = (B == F && E != I) || (H == F && E != C) ? F : E; + outputBuffer[3*i+2 + width*3*j ] = D == H ? D : E; + outputBuffer[3*i+2 + width*(3*j+1)] = (D == H && E != I) || (H == F && E != G) ? H : E; + outputBuffer[3*i+2 + width*(3*j+2)] = H == F ? F : E; + } else { + outputBuffer[3*i + width*3*j ] = E; + outputBuffer[3*i + width*(3*j+1)] = E; + outputBuffer[3*i + width*(3*j+2)] = E; + outputBuffer[3*i+1 + width*3*j ] = E; + outputBuffer[3*i+1 + width*(3*j+1)] = E; + outputBuffer[3*i+1 + width*(3*j+2)] = E; + outputBuffer[3*i+2 + width*3*j ] = E; + outputBuffer[3*i+2 + width*(3*j+1)] = E; + outputBuffer[3*i+2 + width*(3*j+2)] = E; + } + } + } +} + +static void scale4x ( uint32* inputBuffer, uint32* outputBuffer, int inWidth, int inHeight ) +{ + int width = 2* inWidth; + int height = 2 * inHeight; + uint32 * buffer2x = new uint32[width*height]; + + scale2x ( reinterpret_cast ( inputBuffer ), reinterpret_cast ( buffer2x ), inWidth, inHeight ); + width *= 2; + height *= 2; + scale2x ( reinterpret_cast ( buffer2x ), reinterpret_cast ( outputBuffer ), 2*inWidth, 2*inHeight ); + delete[] buffer2x; +} + + +static unsigned char *scaleNxHelper( void (*scaleNxFunction) ( uint32* , uint32* , int , int), + const int N, + unsigned char *inputBuffer, + const int inWidth, + const int inHeight, + int &outWidth, + int &outHeight ) +{ + outWidth = N * inWidth; + outHeight = N *inHeight; + unsigned char * newBuffer = new unsigned char[outWidth*outHeight*4]; + + scaleNxFunction ( reinterpret_cast ( inputBuffer ), reinterpret_cast ( newBuffer ), inWidth, inHeight ); + delete[] inputBuffer; + return newBuffer; +} + +//=========================================================================== +// +// [BB] Upsamples the texture in inputBuffer, frees inputBuffer and returns +// the upsampled buffer. +// +//=========================================================================== +unsigned char *gl_CreateUpsampledTextureBuffer ( const FGLTexture *inputGLTexture, unsigned char *inputBuffer, const int inWidth, const int inHeight, int &outWidth, int &outHeight ) +{ + // [BB] Don't resample if the width or height of the input texture is bigger than gl_texture_hqresize_maxinputsize. + if ( ( inWidth > gl_texture_hqresize_maxinputsize ) || ( inHeight > gl_texture_hqresize_maxinputsize ) ) + return inputBuffer; + + // [BB] The hqnx upsampling (not the scaleN one) destroys partial transparency, don't upsamle textures using it. + if ( inputGLTexture->bIsTransparent == 1 ) + return inputBuffer; + + switch (inputGLTexture->tex->UseType) + { + case FTexture::TEX_Sprite: + case FTexture::TEX_SkinSprite: + if (!(gl_texture_hqresize_targets & 2)) return inputBuffer; + break; + + case FTexture::TEX_FontChar: + if (!(gl_texture_hqresize_targets & 4)) return inputBuffer; + break; + + default: + if (!(gl_texture_hqresize_targets & 1)) return inputBuffer; + break; + } + + if (inputBuffer) + { + outWidth = inWidth; + outHeight = inHeight; + int type = gl_texture_hqresize; + switch (type) + { + case 1: + return scaleNxHelper( &scale2x, 2, inputBuffer, inWidth, inHeight, outWidth, outHeight ); + case 2: + return scaleNxHelper( &scale3x, 3, inputBuffer, inWidth, inHeight, outWidth, outHeight ); + case 3: + return scaleNxHelper( &scale4x, 4, inputBuffer, inWidth, inHeight, outWidth, outHeight ); + } + } + return inputBuffer; +} diff --git a/src/gl/gl_hqresize.h b/src/gl/gl_hqresize.h new file mode 100644 index 00000000..50d08d6c --- /dev/null +++ b/src/gl/gl_hqresize.h @@ -0,0 +1,43 @@ +/* +** gl_hqresize.h +** Contains high quality upsampling functions. +** +**--------------------------------------------------------------------------- +** Copyright 2008 Benjamin Berkels +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef __GL_HQRESIZE_H__ +#define __GL_HQRESIZE_H__ + +#include "gl_texture.h" + +unsigned char *gl_CreateUpsampledTextureBuffer ( const FGLTexture *inputGLTexture, unsigned char *inputBuffer, const int inWidth, const int inHeight, int &outWidth, int &outHeight ); + +#endif // __GL_HQRESIZE_H__ + diff --git a/src/gl/gl_menu.cpp b/src/gl/gl_menu.cpp index 94cff235..5b2715c2 100644 --- a/src/gl/gl_menu.cpp +++ b/src/gl/gl_menu.cpp @@ -39,6 +39,10 @@ EXTERN_CVAR (Bool, gl_lights_additive) EXTERN_CVAR (Float, gl_light_ambient) EXTERN_CVAR(Int, gl_billboard_mode) EXTERN_CVAR(Int, gl_particles_style) +EXTERN_CVAR(Int, gl_texture_hqresize) +EXTERN_CVAR(Flag, gl_texture_hqresize_textures) +EXTERN_CVAR(Flag, gl_texture_hqresize_sprites) +EXTERN_CVAR(Flag, gl_texture_hqresize_fonts) static value_t SpriteclipModes[]= { @@ -133,6 +137,20 @@ static value_t Particles[] = { 2.0, "Smooth" }, }; +static value_t HqResizeModes[] = +{ + { 0.0, "Off" }, + { 1.0, "Scale2x" }, + { 2.0, "Scale3x" }, + { 3.0, "Scale4x" }, +}; + +static value_t HqResizeTargets[] = +{ + { 0.0, "Everything" }, + { 1.0, "Sprites/fonts" }, +}; + static value_t FogMode[] = { { 0.0, "Off" }, @@ -168,6 +186,10 @@ menuitem_t GLTextureItems[] = { { discrete, "Anisotropic filter", {&gl_texture_filter_anisotropic},{5.0},{0.0}, {0.0}, {Anisotropy} }, { discrete, "Texture Format", {&gl_texture_format}, {8.0}, {0.0}, {0.0}, {TextureFormats} }, { discrete, "Enable hires textures", {&gl_texture_usehires}, {2.0}, {0.0}, {0.0}, {YesNo} }, + { discrete, "High Quality Resize mode", {&gl_texture_hqresize}, {4.0}, {0.0}, {0.0}, {HqResizeModes} }, + { discrete, "Resize textures", {&gl_texture_hqresize_textures},{2.0}, {0.0}, {0.0}, {OnOff} }, + { discrete, "Resize sprites", {&gl_texture_hqresize_sprites}, {2.0}, {0.0}, {0.0}, {OnOff} }, + { discrete, "Resize fonts", {&gl_texture_hqresize_fonts}, {2.0}, {0.0}, {0.0}, {OnOff} }, { discrete, "Precache GL textures", {&gl_precache}, {2.0}, {0.0}, {0.0}, {YesNo} }, }; diff --git a/src/gl/gl_missinglines.cpp b/src/gl/gl_missinglines.cpp deleted file mode 100644 index a150220f..00000000 --- a/src/gl/gl_missinglines.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* -** gl_missinglines.cpp -** This mess is only needed because ZDBSP likes to throw out lines -** out of the BSP if they overlap -** -**--------------------------------------------------------------------------- -** Copyright 2005 Christoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be -** covered by the terms of the GNU Lesser General Public License as published -** by the Free Software Foundation; either version 2.1 of the License, or (at -** your option) any later version. -** 5. Full disclosure of the entire project's source code, except for third -** party libraries is mandatory. (NOTE: This clause is non-negotiable!) -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ -#include "gl/gl_include.h" -#include "p_local.h" -#include "gl/gl_struct.h" -#include "gl/gl_renderstruct.h" -#include "gl/gl_glow.h" -#include "gl/gl_data.h" -#include "gl/gl_basic.h" -#include "gl/gl_functions.h" -#include "gl/gl_geometric.h" - -static seg_t * compareseg; -int firstmissingseg; - -static int STACK_ARGS segcmp(const void * a, const void * b) -{ - seg_t * seg1 = *((seg_t**)a); - seg_t * seg2 = *((seg_t**)b); - - return - P_AproxDistance(seg2->v1->x - compareseg->v1->x, seg2->v1->y - compareseg->v1->y) - - P_AproxDistance(seg1->v1->x - compareseg->v1->x, seg1->v1->y - compareseg->v1->y); - - //return (seg2->v1 - compareseg->v1).LengthSquared() - (seg1->v1 - compareseg->v1).LengthSquared(); -} - -//========================================================================== -// -// Collect all sidedefs which are not entirely covered by segs -// -// (Sigh! Why do I have to compensate for ZDBSP's shortcomings...) -// -//========================================================================== - -void gl_CollectMissingLines() -{ - firstmissingseg=numsegs; - - TArray MissingSides; - TArray * linesegs = new TArray[numsides]; - - float * added_seglen = new float[numsides]; - - memset(added_seglen, 0, sizeof(float)*numsides); - for(int i=0;isidedef!=NULL) - { - // collect all the segs and calculate the length they occupy on their sidedef - - //added_seglen[seg->linedef-lines + side]+= (*seg->v2 - *seg->v1).Length(); -#ifdef _MSC_VER - added_seglen[seg->sidedef - sides]+= (Vector(seg->v2)-Vector(seg->v1)).Length(); -#else - Vector vec1(Vector(seg->v1)); - Vector vec2(Vector(seg->v2)); - Vector tmpVec = vec2-vec1; - added_seglen[seg->sidedef - sides]+= tmpVec.Length(); -#endif - linesegs[seg->sidedef - sides].Push(seg); - } - } - MissingSides.Clear(); - for(int i=0;ilinenum]; - - //float linelen = (*line->v2 - *line->v1).Length(); -#ifdef _MSC_VER - float linelen = (Vector(line->v2)-Vector(line->v1)).Length(); -#else - Vector vec1(Vector(line->v1)); - Vector vec2(Vector(line->v2)); - Vector tmpVec = (vec2-vec1); - float linelen = tmpVec.Length(); -#endif - - if (added_seglen[i] < linelen -1) - { - Printf("Sidedef %d (linedef %d) incomplete (Length = %f of %f)\n", - i,side->linenum, added_seglen[i], linelen); - - // create a seg for the sidedef - seg_t seg; - seg.sidedef = side; - seg.linedef = line; - if (side == &sides[line->sidenum[0]]) - { - seg.v1 = line->v1; - seg.v2 = line->v2; - seg.frontsector = line->frontsector; - seg.backsector = line->backsector; - } - else - { - seg.v2 = line->v1; - seg.v1 = line->v2; - seg.backsector = line->frontsector; - seg.frontsector = line->backsector; - } - seg.Subsector = NULL; - seg.PartnerSeg=NULL; - seg.bPolySeg=false; - - if (linesegs[i].Size()!=0) - { - // There are already segs for this line so - // we have to fill in the gaps. To make polyobject - // spawning possible the sidedef has do be properly - // split into segs that span its entire length - compareseg = &seg; - - // Sort the segs so inserting new ones becomes easier - qsort(&linesegs[i][0], linesegs[i].Size(), sizeof(seg_t*), segcmp); - - for(unsigned int j=0;jv1 != seg.v1) - { - seg_t newseg = seg; - newseg.v2 = linesegs[i][j]->v1; - MissingSides.Push(newseg); - } - seg.v1 = linesegs[i][j]->v2; - } - } - if (seg.v1!=seg.v2) - { - MissingSides.Push(seg); - } - } - } - - if (MissingSides.Size()) - { - // Now we have to add the newly created segs to the segs array so - // that the polyobject spawn code has access to them. - seg_t * newsegs = new seg_t[numsegs + MissingSides.Size()]; - - memcpy(newsegs, segs, sizeof(seg_t) * numsegs); - memcpy(newsegs+numsegs, &MissingSides[0], sizeof(seg_t)*MissingSides.Size()); - for(int i = 0; i < numsegs; i++) - { - if (newsegs[i].PartnerSeg && newsegs[i].PartnerSeg>=segs && newsegs[i].PartnerSeglinedef->validcount==validcount) continue; - - // Don't draw lines facing away from the viewer - divline_t dl = { seg->v1->x, seg->v1->y, seg->v2->x-seg->v1->x, seg->v2->y-seg->v1->y }; - if (P_PointOnDivlineSide(viewx, viewy, &dl)) continue; - - // Unfortunately there is no simple means to exclude lines here so we have - // to draw them all. - sector_t ffakesec, bfakesec; - - sector_t * sector = gl_FakeFlat(seg->frontsector, &ffakesec, false); - sector_t * backsector; - - if (seg->frontsector == seg->backsector) backsector=sector; - else if (!seg->backsector) backsector=NULL; - else backsector = gl_FakeFlat(seg->backsector, &bfakesec, true); - - GLWall wall; - - SetupWall.Clock(); - - wall.Process(seg, sector, backsector, NULL); - rendered_lines++; - - SetupWall.Unclock(); - } -} diff --git a/src/gl/gl_missingtexture.cpp b/src/gl/gl_missingtexture.cpp index af633213..f18d4b63 100644 --- a/src/gl/gl_missingtexture.cpp +++ b/src/gl/gl_missingtexture.cpp @@ -55,7 +55,6 @@ // This is for debugging maps. CVAR(Bool, gl_notexturefill, false, 0); -extern int firstmissingseg; FreeList SSR_List; @@ -939,7 +938,7 @@ ADD_STAT(missingtextures) void GLDrawInfo::AddHackedSubsector(subsector_t * sub) { - if (firstmissingseg==numsegs && !(level.flags & LEVEL_HEXENFORMAT)) + if (!(level.flags & LEVEL_HEXENFORMAT)) { SubsectorHackInfo sh={sub, 0}; SubsectorHacks.Push (sh); diff --git a/src/gl/gl_nodes.cpp b/src/gl/gl_nodes.cpp index dd99b15c..e3a1d8c9 100644 --- a/src/gl/gl_nodes.cpp +++ b/src/gl/gl_nodes.cpp @@ -57,6 +57,7 @@ #include "doomerrors.h" #include "p_setup.h" #include "x86.h" +#include "version.h" node_t * gamenodes; int numgamenodes; @@ -108,6 +109,49 @@ typedef struct } gl5_mapnode_t; #define GL5_NF_SUBSECTOR (1 << 31) + + +//========================================================================== +// +// Collect all sidedefs which are not entirely covered by segs +// Old ZDBSPs could create such maps. If such a BSP is discovered +// a node rebuild must be done to ensure proper rendering +// +//========================================================================== + +int gl_CheckForMissingSegs() +{ + float *added_seglen = new float[numsides]; + int missing = 0; + + memset(added_seglen, 0, sizeof(float)*numsides); + for(int i=0;isidedef!=NULL) + { + // check all the segs and calculate the length they occupy on their sidedef + TVector2 vec1(seg->v2->x - seg->v1->x, seg->v2->y - seg->v1->y); + added_seglen[seg->sidedef - sides] += float(vec1.Length()); + } + } + + for(int i=0;ilinenum]; + + TVector2 lvec(line->dx, line->dy); + float linelen = float(lvec.Length()); + + missing += (added_seglen[i] < linelen - 1); + } + + delete [] added_seglen; + return missing; +} + //========================================================================== // // Checks whether the nodes are suitable for GL rendering @@ -144,7 +188,13 @@ bool gl_CheckForGLNodes() } // all subsectors were closed but there are no minisegs // Although unlikely this can happen. Such nodes are not a problem. - return true; + // all that is left is to check whether the BSP covers all sidedefs completely. + int missing = gl_CheckForMissingSegs(); + if (missing > 0) + { + Printf("%d missing segs counted\nThe BSP needs to be rebuilt", missing); + } + return missing == 0; } @@ -186,7 +236,7 @@ static bool gl_LoadVertexes(FileReader * f, wadlump_t * lump) // GLNodes V1 and V4 are unsupported. // V1 because the precision is insufficient and // V4 due to the missing partner segs - Printf("GL nodes v%d found. This format is not supported by GZDoom\n", + Printf("GL nodes v%d found. This format is not supported by "GAMENAME"\n", (*(int *)gldata == gNd4)? 4:1); delete [] gldata; @@ -256,7 +306,9 @@ bool gl_LoadGLSegs(FileReader * f, wadlump_t * lump) f->Read(data, lump->Size); segs=NULL; - try +#ifdef _MSC_VER + __try +#endif { if (!format5 && memcmp(data, "gNd3", 4)) { @@ -346,16 +398,19 @@ bool gl_LoadGLSegs(FileReader * f, wadlump_t * lump) delete [] data; return true; } - catch(...) +#ifdef _MSC_VER + __except(1) { // Invalid data has the bas habit of requiring extensive checks here // so let's just catch anything invalid and output a message. + // (at least under MSVC. GCC can't do SEH even for Windows... :( ) Printf("Invalid GL segs. The BSP will have to be rebuilt.\n"); delete [] data; delete [] segs; segs = NULL; return false; } +#endif } @@ -612,7 +667,7 @@ bool gl_DoLoadGLNodes(FileReader * f, wadlump_t * lumps) seg_t * seg = &segs[subsectors[i].firstline]; if (!seg->sidedef) { - Printf("GWA file contains invalid nodes. The BSP has to be rebuilt.\n"); + Printf("GL nodes contain invalid data. The BSP has to be rebuilt.\n"); delete [] nodes; nodes = NULL; delete [] subsectors; @@ -622,7 +677,14 @@ bool gl_DoLoadGLNodes(FileReader * f, wadlump_t * lumps) return false; } } - return true; + + // check whether the BSP covers all sidedefs completely. + int missing = gl_CheckForMissingSegs(); + if (missing > 0) + { + Printf("%d missing segs counted in GL nodes.\nThe BSP has to be rebuilt", missing); + } + return missing == 0; } @@ -898,5 +960,4 @@ void gl_CheckNodes(MapData * map) gamesubsectors = subsectors; numgamesubsectors = numsubsectors; } - } diff --git a/src/gl/gl_renderstruct.h b/src/gl/gl_renderstruct.h index 9b970807..95858269 100644 --- a/src/gl/gl_renderstruct.h +++ b/src/gl/gl_renderstruct.h @@ -247,7 +247,7 @@ private: public: - void Process(seg_t *seg, sector_t * frontsector, sector_t * backsector, subsector_t * polysub); + void Process(seg_t *seg, sector_t * frontsector, sector_t * backsector, subsector_t * polysub, bool render_segs); void ProcessLowerMiniseg(seg_t *seg, sector_t * frontsector, sector_t * backsector); void Draw(int pass); diff --git a/src/gl/gl_scene.cpp b/src/gl/gl_scene.cpp index 4c5164f1..b6529a43 100644 --- a/src/gl/gl_scene.cpp +++ b/src/gl/gl_scene.cpp @@ -342,7 +342,6 @@ static void ProcessScene() // And now the crappy hacks that have to be done to avoid rendering anomalies: - gl_RenderMissingLines(); // Omitted lines by the node builder gl_drawinfo->HandleMissingTextures(); // Missing upper/lower textures gl_drawinfo->HandleHackedSubsectors(); // open sector hacks for deep water gl_drawinfo->ProcessSectorStacks(); // merge visplanes of sector stacks diff --git a/src/gl/gl_sections.cpp b/src/gl/gl_sections.cpp index dd6ad9c2..56032fef 100644 --- a/src/gl/gl_sections.cpp +++ b/src/gl/gl_sections.cpp @@ -163,6 +163,8 @@ public: line.sidedef = seg->sidedef; line.linedef = seg->linedef; line.refseg = seg; + line.polysub = NULL; + line.otherside = -1; if (loop->numlines == 0) { diff --git a/src/gl/gl_shader.cpp b/src/gl/gl_shader.cpp index 590cc58e..827b33a4 100644 --- a/src/gl/gl_shader.cpp +++ b/src/gl/gl_shader.cpp @@ -625,7 +625,7 @@ void GLShader::Bind(int cm, int lightmode, float Speed) void GLShader::Unbind() { - if (gl.flags & RFL_GLSL) + if ((gl.flags & RFL_GLSL) && gl_activeShader != NULL) { gl.UseProgramObjectARB(0); gl_activeShader=NULL; diff --git a/src/gl/gl_struct.h b/src/gl/gl_struct.h index 2a36a82e..93a19447 100644 --- a/src/gl/gl_struct.h +++ b/src/gl/gl_struct.h @@ -159,11 +159,9 @@ struct FGLSectionLine vertex_t *end; side_t *sidedef; line_t *linedef; - union - { - int otherside; - seg_t *refseg; - }; + seg_t *refseg; // we need to reference at least one seg for each line. + subsector_t *polysub; // If this is part of a polyobject we need a reference to the containing subsector + int otherside; }; struct FGLSectionLoop diff --git a/src/gl/gl_texture.cpp b/src/gl/gl_texture.cpp index f8b6bb32..77acd060 100644 --- a/src/gl/gl_texture.cpp +++ b/src/gl/gl_texture.cpp @@ -59,6 +59,7 @@ #include "gl/gl_functions.h" #include "gl/gl_shader.h" #include "gl/gl_translate.h" +#include "gl/gl_hqresize.h" CUSTOM_CVAR(Bool, gl_texture_usehires, true, CVAR_ARCHIVE|CVAR_NOINITCALL) { @@ -1164,6 +1165,9 @@ unsigned char * FGLTexture::CreateTexBuffer(ETexUse use, int _cm, int translatio tex->FTexture::CopyTrueColorPixels(&bmp, GetLeftOffset(use) - tex->LeftOffset, GetTopOffset(use) - tex->TopOffset); } + // [BB] Potentially upsample the buffer. + buffer = gl_CreateUpsampledTextureBuffer ( this, buffer, W, H, w, h ); + if ((!(gl.flags & RFL_GLSL) || !gl_warp_shader) && tex->bWarped && W <= 256 && H <= 256) { buffer = WarpBuffer(buffer, W, H, tex->bWarped); @@ -1209,7 +1213,7 @@ const PatchTextureInfo * FGLTexture::GetPatchTextureInfo() //=========================================================================== // -// Checls if a shader needs to be used for this texture +// Checks if a shader needs to be used for this texture // //=========================================================================== diff --git a/src/gl/gl_walls.cpp b/src/gl/gl_walls.cpp index 4486faea..da65771e 100644 --- a/src/gl/gl_walls.cpp +++ b/src/gl/gl_walls.cpp @@ -1364,7 +1364,7 @@ void GLWall::DoFFloorBlocks(seg_t * seg,sector_t * frontsector,sector_t * backse // // //========================================================================== -void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector, subsector_t * polysub) +void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector, subsector_t * polysub, bool render_segs) { vertex_t * v1, * v2; fixed_t fch1; @@ -1410,7 +1410,7 @@ void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector, glseg.fracleft=0; glseg.fracright=1; - if (gl_render_segs) + if (render_segs) { if (abs(v1->x-v2->x) > abs(v1->y-v2->y)) { diff --git a/src/m_menu.cpp b/src/m_menu.cpp index 09ad5db5..96b69e8a 100644 --- a/src/m_menu.cpp +++ b/src/m_menu.cpp @@ -267,6 +267,8 @@ static FSaveGameNode NewSaveNode; static int epi; // Selected episode +static const char *saved_playerclass = NULL; + // PRIVATE MENU DEFINITIONS ------------------------------------------------ // @@ -1821,15 +1823,18 @@ void M_Episode (int choice) if (AllSkills.Size() == 1) { + saved_playerclass = NULL; M_ChooseSkill(0); return; } else if (EpisodeNoSkill[choice]) { + saved_playerclass = NULL; M_ChooseSkill(AllSkills.Size() == 2? 1:2); return; } - M_StartupSkillMenu(NULL); + M_StartupSkillMenu(saved_playerclass); + saved_playerclass = NULL; } //========================================================================== @@ -1856,6 +1861,7 @@ static void SCClass (int option) if (EpiDef.numitems > 1) { + saved_playerclass = playerclass; M_SetupNextMenu (&EpiDef); } else if (AllSkills.Size() == 1) @@ -1888,6 +1894,7 @@ static void M_ChooseClass (int choice) if (EpiDef.numitems > 1) { + saved_playerclass = playerclass; M_SetupNextMenu (&EpiDef); } else if (AllSkills.Size() == 1) diff --git a/src/m_options.cpp b/src/m_options.cpp index 65508df0..accc9e45 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -1044,17 +1044,25 @@ static menuitem_t DMFlagsItems[] = { { bitflag, "Infinite ammo", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_INFINITE_AMMO} }, { bitflag, "Infinite inventory", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_INFINITE_INVENTORY} }, { bitflag, "No monsters", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_NO_MONSTERS} }, + { bitflag, "No monsters to exit", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_KILL_MONSTERS} }, { bitflag, "Monsters respawn", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_MONSTERS_RESPAWN} }, { bitflag, "No respawn", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_NO_RESPAWN} }, { bitflag, "Items respawn", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_ITEMS_RESPAWN} }, { bitflag, "Big powerups respawn", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_RESPAWN_SUPER} }, { bitflag, "Fast monsters", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_FAST_MONSTERS} }, { bitflag, "Degeneration", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_YES_DEGENERATION} }, + { bitflag, "Allow Autoaim", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_NOAUTOAIM} }, + { bitflag, "Disallow Suicide", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_NOSUICIDE} }, { bitmask, "Allow jump", {&dmflags}, {3.0}, {DF_NO_JUMP|DF_YES_JUMP}, {0}, {DF_Jump} }, { bitmask, "Allow crouch", {&dmflags}, {3.0}, {DF_NO_CROUCH|DF_YES_CROUCH}, {0}, {DF_Crouch} }, { bitflag, "Allow freelook", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_FREELOOK} }, { bitflag, "Allow FOV", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_FOV} }, { bitflag, "Allow BFG aiming", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_NO_FREEAIMBFG} }, + { bitflag, "Allow automap", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_NO_AUTOMAP} }, + { bitflag, "Automap allies", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_NO_AUTOMAP_ALLIES} }, + { bitflag, "Allow spying", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_DISALLOW_SPYING} }, + { bitflag, "Chasecam cheat", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_CHASECAM} }, + { redtext, " ", {NULL}, {0}, {0}, {0}, {NULL} }, { whitetext,"Deathmatch Settings", {NULL}, {0}, {0}, {0}, {NULL} }, { bitflag, "Weapons stay", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_WEAPONS_STAY} }, diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 6d3767ce..5f594870 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1451,6 +1451,10 @@ CCMD (kill) } else { + // If suiciding is disabled, then don't do it. + if (dmflags2 & DF2_NOSUICIDE) + return; + // Kill the player Net_WriteByte (DEM_SUICIDE); } diff --git a/src/p_spec.cpp b/src/p_spec.cpp index c831e1a5..f128e812 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -135,6 +135,10 @@ bool CheckIfExitIsGood (AActor *self, level_info_t *info) if (self == NULL) return true; + // We must kill all monsters to exit the level. + if ((dmflags2 & DF2_KILL_MONSTERS) && level.killed_monsters != level.total_monsters) + return false; + // Is this a deathmatch game and we're not allowed to exit? if ((deathmatch || alwaysapplydmflags) && (dmflags & DF_NO_EXIT)) { diff --git a/src/p_user.cpp b/src/p_user.cpp index 49a2e716..1eca9eb5 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -686,6 +686,31 @@ AWeapon *APlayerPawn::PickNewWeapon (const PClass *ammotype) return best; } + +//=========================================================================== +// +// APlayerPawn :: CheckWeaponSwitch +// +// Checks if weapons should be changed after picking up ammo +// +//=========================================================================== + +void APlayerPawn::CheckWeaponSwitch(const PClass *ammotype) +{ + if (!player->userinfo.neverswitch && + player->PendingWeapon == WP_NOCHANGE && + (player->ReadyWeapon == NULL || + (player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))) + { + AWeapon *best = BestWeapon (ammotype); + if (best != NULL && (player->ReadyWeapon == NULL || + best->SelectionOrder < player->ReadyWeapon->SelectionOrder)) + { + player->PendingWeapon = best; + } + } +} + //=========================================================================== // // APlayerPawn :: GiveDeathmatchInventory diff --git a/src/svnrevision.h b/src/svnrevision.h index 508b9fb5..e21f7927 100644 --- a/src/svnrevision.h +++ b/src/svnrevision.h @@ -3,5 +3,5 @@ // This file was automatically generated by the // updaterevision tool. Do not edit by hand. -#define ZD_SVN_REVISION_STRING "1327" -#define ZD_SVN_REVISION_NUMBER 1327 +#define ZD_SVN_REVISION_STRING "1333" +#define ZD_SVN_REVISION_NUMBER 1333 diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index 69d6a494..9c88e87d 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -325,7 +325,14 @@ do_stop: sc.ScriptError("Negative jump offsets are not allowed"); } - x = new FxStateByIndex(bag.statedef.GetStateCount() + v, sc); + if (x > 0) + { + x = new FxStateByIndex(bag.statedef.GetStateCount() + v, sc); + } + else + { + x = new FxConstant((FState*)NULL, sc); + } } else {