- sync with trunk r1152.

git-svn-id: http://mancubus.net/svn/hosted/gzdoom/branches/voxels@1154 b0f79afe-0144-0410-b225-9a4edf0717df
This commit is contained in:
Christoph Oelckers 2011-01-02 22:39:30 +00:00
commit b02a00e89c
210 changed files with 5513 additions and 3227 deletions

View file

@ -2312,10 +2312,6 @@
<Filter
Name="Render Sources"
>
<File
RelativePath=".\src\r_anim.cpp"
>
</File>
<File
RelativePath=".\src\r_bsp.cpp"
>
@ -2436,6 +2432,14 @@
<Filter
Name="Textures"
>
<File
RelativePath=".\src\textures\anim_switches.cpp"
>
</File>
<File
RelativePath=".\src\textures\animations.cpp"
>
</File>
<File
RelativePath=".\src\textures\automaptexture.cpp"
>

View file

@ -1,5 +1,5 @@
===============================================================================
Universal Doom Map Format ZDoom extensions v1.10 - 25.04.2010
Universal Doom Map Format ZDoom extensions v1.15 - 14.12.2010
Copyright (c) 2008 Christoph Oelckers.
@ -84,6 +84,12 @@ field to 'strifeally', even for the 'Doom' namespace.
In addition to the standard fields, ZDoom defines the following:
Note: All <bool> fields default to false unless mentioned otherwise.
vertex
{
zfloor = <float>; // Floor height at this vertex. Only applies to triangular sectors
zceiling = <float>; // Ceiling height at this vertex. Only applies to triangular sectors
}
linedef
{
alpha = <float>; // Translucency of this line, default is 1.0
@ -153,6 +159,8 @@ Note: All <bool> fields default to false unless mentioned otherwise.
// relative to the owning sector's light level.
lightceilingabsolute = <bool>; // true = 'lightceiling' is an absolute value. Default is
// relative to the owning sector's light level.
alphafloor = <float>; // translucency of floor plane (only has meaning with Sector_SetPortal) Default is 1.0.
alphaceiling = <float>; // translucency of ceiling plane (only has meaning with Sector_SetPortal) Default is 1.0.
gravity = <float>; // Sector's gravity. Default is 1.0.
lightcolor = <integer>; // Sector'S light color as RRGGBB value, default = 0xffffff.
fadecolor = <integer>; // Sector'S fog color as RRGGBB value, default = 0x000000.
@ -281,6 +289,9 @@ Added 'hidden' sector property.
1.14 19.09.2010
Added 'countsecret' actor property.
1.15 14.12.2010
Added vertex floor and ceiling height properties
===============================================================================
EOF
===============================================================================

View file

@ -396,8 +396,7 @@ endif( SSE_MATTERS )
if( CMAKE_COMPILER_IS_GNUCXX )
if( PROFILE )
set( CMAKE_C_FLinclude( FindFluidSynth.cmake )
AGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" )
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" )
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg" )
set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -pg" )
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -pg" )
@ -727,7 +726,6 @@ add_executable( zdoom WIN32
p_xlat.cpp
parsecontext.cpp
po_man.cpp
r_anim.cpp
r_bsp.cpp
r_data.cpp
r_draw.cpp
@ -911,6 +909,8 @@ add_executable( zdoom WIN32
sound/music_timidity_mididevice.cpp
sound/music_win_mididevice.cpp
sound/music_pseudo_mididevice.cpp
textures/animations.cpp
textures/anim_switches.cpp
textures/automaptexture.cpp
textures/bitmap.cpp
textures/buildtexture.cpp

View file

@ -529,7 +529,12 @@ struct FDropItem
class FDropItemPtrArray : public TArray<FDropItem *>
{
public:
~FDropItemPtrArray();
~FDropItemPtrArray()
{
Clear();
}
void Clear();
};
extern FDropItemPtrArray DropItemList;

View file

@ -64,6 +64,12 @@
#include "po_man.h"
#include "a_keys.h"
//=============================================================================
//
// Automap colors
//
//=============================================================================
struct AMColor
{
int Index;
@ -85,7 +91,7 @@ struct AMColor
static AMColor Background, YourColor, WallColor, TSWallColor,
FDWallColor, CDWallColor, ThingColor,
ThingColor_Item, ThingColor_CountItem, ThingColor_Monster, ThingColor_Friend,
SecretWallColor, GridColor, XHairColor,
SpecialWallColor, SecretWallColor, GridColor, XHairColor,
NotSeenColor,
LockedColor,
AlmostBackground,
@ -119,6 +125,12 @@ static BYTE RavenPaletteVals[11*3] =
0, 0, 0, 0, 0, 0,
};
//=============================================================================
//
// globals
//
//=============================================================================
#define MAPBITS 12
#define MapDiv SafeDivScale12
#define MapMul MulScale12
@ -155,6 +167,7 @@ CVAR (Color, am_backcolor, 0x6c5440, CVAR_ARCHIVE);
CVAR (Color, am_yourcolor, 0xfce8d8, CVAR_ARCHIVE);
CVAR (Color, am_wallcolor, 0x2c1808, CVAR_ARCHIVE);
CVAR (Color, am_secretwallcolor, 0x000000, CVAR_ARCHIVE);
CVAR (Color, am_specialwallcolor, 0xffffff, CVAR_ARCHIVE);
CVAR (Color, am_tswallcolor, 0x888888, CVAR_ARCHIVE);
CVAR (Color, am_fdwallcolor, 0x887058, CVAR_ARCHIVE);
CVAR (Color, am_cdwallcolor, 0x4c3820, CVAR_ARCHIVE);
@ -165,6 +178,7 @@ CVAR (Color, am_notseencolor, 0x6c6c6c, CVAR_ARCHIVE);
CVAR (Color, am_lockedcolor, 0x007800, CVAR_ARCHIVE);
CVAR (Color, am_ovyourcolor, 0xfce8d8, CVAR_ARCHIVE);
CVAR (Color, am_ovwallcolor, 0x00ff00, CVAR_ARCHIVE);
CVAR (Color, am_ovspecialwallcolor, 0xffffff, CVAR_ARCHIVE);
CVAR (Color, am_ovthingcolor, 0xe88800, CVAR_ARCHIVE);
CVAR (Color, am_ovotherwallscolor, 0x008844, CVAR_ARCHIVE);
CVAR (Color, am_ovunseencolor, 0x00226e, CVAR_ARCHIVE);
@ -176,6 +190,7 @@ CVAR (Color, am_ovsecretsectorcolor,0x00ffff, CVAR_ARCHIVE);
CVAR (Int, am_map_secrets, 1, CVAR_ARCHIVE);
CVAR (Bool, am_drawmapback, true, CVAR_ARCHIVE);
CVAR (Bool, am_showkeys, true, CVAR_ARCHIVE);
CVAR (Bool, am_showtriggerlines, false, CVAR_ARCHIVE);
CVAR (Color, am_thingcolor_friend, 0xfcfcfc, CVAR_ARCHIVE);
CVAR (Color, am_thingcolor_monster, 0xfcfcfc, CVAR_ARCHIVE);
CVAR (Color, am_thingcolor_item, 0xfcfcfc, CVAR_ARCHIVE);
@ -287,72 +302,28 @@ struct islope_t
// A line drawing of the player pointing right,
// starting from the middle.
//
#define R ((8*PLAYERRADIUS)/7)
mline_t player_arrow[] = {
{ { -R+R/8, 0 }, { R, 0 } }, // -----
{ { R, 0 }, { R-R/2, R/4 } }, // ----->
{ { R, 0 }, { R-R/2, -R/4 } },
{ { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >---->
{ { -R+R/8, 0 }, { -R-R/8, -R/4 } },
{ { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>--->
{ { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }
};
#define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t))
mline_t player_arrow_raven[] = {
{ { -R+R/4, 0 }, { 0, 0} }, // center line.
{ { -R+R/4, R/8 }, { R, 0} }, // blade
{ { -R+R/4, -R/8 }, { R, 0 } },
{ { -R+R/4, -R/4 }, { -R+R/4, R/4 } }, // crosspiece
{ { -R+R/8, -R/4 }, { -R+R/8, R/4 } },
{ { -R+R/8, -R/4 }, { -R+R/4, -R/4} }, //crosspiece connectors
{ { -R+R/8, R/4 }, { -R+R/4, R/4} },
{ { -R-R/4, R/8 }, { -R-R/4, -R/8 } }, //pommel
{ { -R-R/4, R/8 }, { -R+R/8, R/8 } },
{ { -R-R/4, -R/8}, { -R+R/8, -R/8 } }
};
#define NUMPLYRLINES_RAVEN (sizeof(player_arrow_raven)/sizeof(mline_t))
mline_t cheat_player_arrow[] = {
{ { -R+R/8, 0 }, { R, 0 } }, // -----
{ { R, 0 }, { R-R/2, R/6 } }, // ----->
{ { R, 0 }, { R-R/2, -R/6 } },
{ { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >----->
{ { -R+R/8, 0 }, { -R-R/8, -R/6 } },
{ { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>----->
{ { -R+3*R/8, 0 }, { -R+R/8, -R/6 } },
{ { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d--->
{ { -R/2, -R/6 }, { -R/2+R/6, -R/6 } },
{ { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } },
{ { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd-->
{ { -R/6, -R/6 }, { 0, -R/6 } },
{ { 0, -R/6 }, { 0, R/4 } },
{ { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt->
{ { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } },
{ { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } }
};
#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t))
#undef R
static TArray<mline_t> MapArrow;
static TArray<mline_t> CheatMapArrow;
static TArray<mline_t> CheatKey;
#define R (MAPUNIT)
// [RH] Avoid lots of warnings without compiler-specific #pragmas
#define L(a,b,c,d) { {(fixed_t)((a)*R),(fixed_t)((b)*R)}, {(fixed_t)((c)*R),(fixed_t)((d)*R)} }
mline_t triangle_guy[] = {
static mline_t triangle_guy[] = {
L (-.867,-.5, .867,-.5),
L (.867,-.5, 0,1),
L (0,1, -.867,-.5)
};
#define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t))
mline_t thintriangle_guy[] = {
static mline_t thintriangle_guy[] = {
L (-.5,-.7, 1,0),
L (1,0, -.5,.7),
L (-.5,.7, -.5,-.7)
};
#define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t))
mline_t square_guy[] = {
static mline_t square_guy[] = {
L (0,1,1,0),
L (1,0,0,-1),
L (0,-1,-1,0),
@ -361,26 +332,6 @@ mline_t square_guy[] = {
#define NUMSQUAREGUYLINES (sizeof(square_guy)/sizeof(mline_t))
#undef R
#define R (MAPUNIT)
mline_t key_guy[] = {
L (-2, 0, -1.7, -0.5),
L (-1.7, -0.5, -1.5, -0.7),
L (-1.5, -0.7, -0.8, -0.5),
L (-0.8, -0.5, -0.6, 0),
L (-0.6, 0, -0.8, 0.5),
L (-1.5, 0.7, -0.8, 0.5),
L (-1.7, 0.5, -1.5, 0.7),
L (-2, 0, -1.7, 0.5),
L (-0.6, 0, 2, 0),
L (1.7, 0, 1.7, -1),
L (1.5, 0, 1.5, -1),
L (1.3, 0, 1.3, -1)
};
#define NUMKEYGUYLINES (sizeof(key_guy)/sizeof(mline_t))
#undef L
#undef R
@ -396,8 +347,6 @@ CUSTOM_CVAR (Int, am_cheat, 0, 0)
static int grid = 0;
static int leveljuststarted = 1; // kluge until AM_LevelInit() is called
bool automapactive = false;
// location of window on screen
@ -449,8 +398,6 @@ static FTextureID marknums[10]; // numbers used for marking by the automap
static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are
static int markpointnum = 0; // next point to be assigned
static int followplayer = 1; // specifies whether to follow the player around
static FTextureID mapback; // the automap background
static fixed_t mapystart=0; // y-value for the start of the map bitmap...used in the parallax stuff.
static fixed_t mapxstart=0; //x-value for the bitmap.
@ -476,11 +423,14 @@ void AM_restoreScaleAndLoc ();
void AM_minOutWindowScale ();
CVAR(Bool, am_followplayer, true, CVAR_ARCHIVE)
CCMD(am_togglefollow)
{
followplayer = !followplayer;
am_followplayer = !am_followplayer;
f_oldloc.x = FIXED_MAX;
Printf ("%s\n", GStrings(followplayer ? "AMSTR_FOLLOWON" : "AMSTR_FOLLOWOFF"));
Printf ("%s\n", GStrings(am_followplayer ? "AMSTR_FOLLOWON" : "AMSTR_FOLLOWOFF"));
}
CCMD(am_togglegrid)
@ -545,6 +495,76 @@ void AM_getIslope (mline_t *ml, islope_t *is)
}
*/
void AM_ParseArrow(TArray<mline_t> &Arrow, const char *lumpname)
{
const int R = ((8*PLAYERRADIUS)/7);
FScanner sc;
int lump = Wads.CheckNumForFullName(lumpname, true);
if (lump >= 0)
{
sc.OpenLumpNum(lump);
sc.SetCMode(true);
while (sc.GetToken())
{
mline_t line;
sc.TokenMustBe('(');
sc.MustGetFloat();
line.a.x = xs_RoundToInt(sc.Float*R);
sc.MustGetToken(',');
sc.MustGetFloat();
line.a.y = xs_RoundToInt(sc.Float*R);
sc.MustGetToken(')');
sc.MustGetToken(',');
sc.MustGetToken('(');
sc.MustGetFloat();
line.b.x = xs_RoundToInt(sc.Float*R);
sc.MustGetToken(',');
sc.MustGetFloat();
line.b.y = xs_RoundToInt(sc.Float*R);
sc.MustGetToken(')');
Arrow.Push(line);
}
}
}
void AM_StaticInit()
{
MapArrow.Clear();
CheatMapArrow.Clear();
CheatKey.Clear();
if (gameinfo.mMapArrow.IsNotEmpty()) AM_ParseArrow(MapArrow, gameinfo.mMapArrow);
if (gameinfo.mCheatMapArrow.IsNotEmpty()) AM_ParseArrow(CheatMapArrow, gameinfo.mCheatMapArrow);
AM_ParseArrow(CheatKey, "maparrows/key.txt");
if (MapArrow.Size() == 0) I_FatalError("No automap arrow defined");
char namebuf[9];
for (int i = 0; i < 10; i++)
{
mysnprintf (namebuf, countof(namebuf), "AMMNUM%d", i);
marknums[i] = TexMan.CheckForTexture (namebuf, FTexture::TEX_MiscPatch);
}
markpointnum = 0;
mapback.SetInvalid();
static DWORD *lastpal = NULL;
//static int lastback = -1;
DWORD *palette;
palette = (DWORD *)GPalette.BaseColors;
int i, j;
for (i = j = 0; i < 11; i++, j += 3)
{
DoomColors[i].FromRGB(DoomPaletteVals[j], DoomPaletteVals[j+1], DoomPaletteVals[j+2]);
StrifeColors[i].FromRGB(StrifePaletteVals[j], StrifePaletteVals[j+1], StrifePaletteVals[j+2]);
RavenColors[i].FromRGB(RavenPaletteVals[j], RavenPaletteVals[j+1], RavenPaletteVals[j+2]);
}
}
//=============================================================================
//
// called by the coordinate drawer
@ -599,7 +619,7 @@ void AM_restoreScaleAndLoc ()
{
m_w = old_m_w;
m_h = old_m_h;
if (!followplayer)
if (!am_followplayer)
{
m_x = old_m_x;
m_y = old_m_y;
@ -796,7 +816,7 @@ void AM_changeWindowLoc ()
{
if (0 != (m_paninc.x | m_paninc.y))
{
followplayer = 0;
am_followplayer = false;
f_oldloc.x = FIXED_MAX;
}
@ -876,28 +896,11 @@ void AM_initVariables ()
static void AM_initColors (bool overlayed)
{
static DWORD *lastpal = NULL;
//static int lastback = -1;
DWORD *palette;
palette = (DWORD *)GPalette.BaseColors;
if (lastpal != palette)
{
int i, j;
for (i = j = 0; i < 11; i++, j += 3)
{
DoomColors[i].FromRGB(DoomPaletteVals[j], DoomPaletteVals[j+1], DoomPaletteVals[j+2]);
StrifeColors[i].FromRGB(StrifePaletteVals[j], StrifePaletteVals[j+1], StrifePaletteVals[j+2]);
RavenColors[i].FromRGB(RavenPaletteVals[j], RavenPaletteVals[j+1], RavenPaletteVals[j+2]);
}
}
if (overlayed)
{
YourColor.FromCVar (am_ovyourcolor);
WallColor.FromCVar (am_ovwallcolor);
SpecialWallColor.FromCVar(am_ovspecialwallcolor);
SecretWallColor = WallColor;
SecretSectorColor.FromCVar (am_ovsecretsectorcolor);
ThingColor_Item.FromCVar (am_ovthingcolor_item);
@ -920,6 +923,7 @@ static void AM_initColors (bool overlayed)
Background.FromCVar (am_backcolor);
YourColor.FromCVar (am_yourcolor);
SecretWallColor.FromCVar (am_secretwallcolor);
SpecialWallColor.FromCVar (am_specialwallcolor);
WallColor.FromCVar (am_wallcolor);
TSWallColor.FromCVar (am_tswallcolor);
FDWallColor.FromCVar (am_fdwallcolor);
@ -961,6 +965,7 @@ static void AM_initColors (bool overlayed)
AlmostBackground = DoomColors[2];
SecretSectorColor =
SecretWallColor =
SpecialWallColor =
WallColor = DoomColors[3];
TSWallColor = DoomColors[4];
FDWallColor = DoomColors[5];
@ -982,6 +987,7 @@ static void AM_initColors (bool overlayed)
AlmostBackground = DoomColors[2];
SecretSectorColor =
SecretWallColor =
SpecialWallColor =
WallColor = StrifeColors[3];
TSWallColor = StrifeColors[4];
FDWallColor = StrifeColors[5];
@ -1003,6 +1009,7 @@ static void AM_initColors (bool overlayed)
AlmostBackground = DoomColors[2];
SecretSectorColor =
SecretWallColor =
SpecialWallColor =
WallColor = RavenColors[3];
TSWallColor = RavenColors[4];
FDWallColor = RavenColors[5];
@ -1018,30 +1025,6 @@ static void AM_initColors (bool overlayed)
break;
}
lastpal = palette;
}
//=============================================================================
//
//
//
//=============================================================================
void AM_loadPics ()
{
int i;
char namebuf[9];
for (i = 0; i < 10; i++)
{
mysnprintf (namebuf, countof(namebuf), "AMMNUM%d", i);
marknums[i] = TexMan.CheckForTexture (namebuf, FTexture::TEX_MiscPatch);
}
const char *autopage = level.info->mapbg[0] == 0? "AUTOPAGE" : (const char*)&level.info->mapbg[0];
mapback = TexMan.CheckForTexture(autopage, FTexture::TEX_MiscPatch);
}
//=============================================================================
@ -1066,7 +1049,8 @@ bool AM_clearMarks ()
void AM_LevelInit ()
{
leveljuststarted = 0;
const char *autopage = level.info->mapbg[0] == 0? "AUTOPAGE" : (const char*)&level.info->mapbg[0];
mapback = TexMan.CheckForTexture(autopage, FTexture::TEX_MiscPatch);
AM_clearMarks();
@ -1104,7 +1088,6 @@ void AM_Start ()
if (!stopped) AM_Stop();
stopped = false;
AM_initVariables();
AM_loadPics();
}
@ -1216,7 +1199,7 @@ bool AM_Responder (event_t *ev, bool last)
{
if (automapactive && (ev->type == EV_KeyDown || ev->type == EV_KeyUp))
{
if (followplayer)
if (am_followplayer)
{
// check for am_pan* and ignore in follow mode
const char *defbind = AutomapBindings.GetBind(ev->data1);
@ -1329,7 +1312,7 @@ void AM_Ticker ()
amclock++;
if (followplayer)
if (am_followplayer)
{
AM_doFollowPlayer();
}
@ -1549,7 +1532,7 @@ void AM_drawGrid (const AMColor &color)
// [RH] Calculate a minimum for how long the grid lines should be so that
// they cover the screen at any rotation.
minlen = (fixed_t)sqrtf ((float)m_w*(float)m_w + (float)m_h*(float)m_h);
minlen = (fixed_t)sqrt ((double)m_w*(double)m_w + (double)m_h*(double)m_h);
extx = (minlen - m_w) / 2;
exty = (minlen - m_h) / 2;
@ -1861,14 +1844,16 @@ void AM_drawWalls (bool allmap)
else if (lines[i].special == Door_LockedRaise ||
lines[i].special == ACS_LockedExecute ||
lines[i].special == ACS_LockedExecuteDoor ||
(lines[i].special == Generic_Door && lines[i].args[4] !=0 ))
(lines[i].special == Door_Animated && lines[i].args[3] != 0) ||
(lines[i].special == Generic_Door && lines[i].args[4] != 0))
{
if (am_colorset == 0 || am_colorset == 3) // Raven games show door colors
{
int P_GetMapColorForLock(int lock);
int lock;
if (lines[i].special==Door_LockedRaise) lock=lines[i].args[3];
if (lines[i].special==Door_LockedRaise || lines[i].special==Door_Animated)
lock=lines[i].args[3];
else lock=lines[i].args[4];
int color = P_GetMapColorForLock(lock);
@ -1885,6 +1870,17 @@ void AM_drawWalls (bool allmap)
AM_drawMline (&l, LockedColor); // locked special
}
}
else if (am_showtriggerlines && am_colorset == 0 && lines[i].special != 0
&& lines[i].special != Door_Open
&& lines[i].special != Door_Close
&& lines[i].special != Door_CloseWaitOpen
&& lines[i].special != Door_Raise
&& lines[i].special != Door_Animated
&& lines[i].special != Generic_Door
&& (lines[i].activation & SPAC_PlayerActivate))
{
AM_drawMline(&l, SpecialWallColor); // wall with special non-door action the player can do
}
else if (lines[i].backsector == NULL)
{
AM_drawMline(&l, WallColor); // one-sided wall
@ -2047,20 +2043,15 @@ void AM_drawPlayers ()
angle = players[consoleplayer].camera->angle;
}
if (gameinfo.gametype & GAME_Raven)
if (am_cheat != 0 && CheatMapArrow.Size() > 0)
{
arrow = player_arrow_raven;
numarrowlines = NUMPLYRLINES_RAVEN;
}
else if (am_cheat != 0)
{
arrow = cheat_player_arrow;
numarrowlines = NUMCHEATPLYRLINES;
arrow = &CheatMapArrow[0];
numarrowlines = CheatMapArrow.Size();
}
else
{
arrow = player_arrow;
numarrowlines = NUMPLYRLINES;
arrow = &MapArrow[0];
numarrowlines = MapArrow.Size();
}
AM_drawLineCharacter(arrow, numarrowlines, 0, angle, YourColor, pt.x, pt.y);
return;
@ -2113,9 +2104,7 @@ void AM_drawPlayers ()
angle -= players[consoleplayer].camera->angle - ANG90;
}
AM_drawLineCharacter
(player_arrow, NUMPLYRLINES, 0, angle,
color, pt.x, pt.y);
AM_drawLineCharacter(&MapArrow[0], MapArrow.Size(), 0, angle, color, pt.x, pt.y);
}
}
}
@ -2171,7 +2160,7 @@ void AM_drawThings ()
if (c >= 0) color.FromRGB(RPART(c), GPART(c), BPART(c));
else color = ThingColor_CountItem;
AM_drawLineCharacter(key_guy, NUMKEYGUYLINES, 16<<MAPBITS, 0, color, p.x, p.y);
AM_drawLineCharacter(&CheatKey[0], CheatKey.Size(), 0, 0, color, p.x, p.y);
color.Index = -1;
}
else

View file

@ -25,6 +25,9 @@
struct event_t;
class FArchive;
void AM_StaticInit();
// Called by main loop.
bool AM_Responder (event_t* ev, bool last);

View file

@ -105,11 +105,6 @@ FArchive &operator<< (FArchive &arc, botskill_t &skill)
// This is intentionally not in the weapon definition anymore.
void InitBotStuff()
{
static bool done = false;
if (done) return;
done = true;
static struct BotInit
{
const char *type;

View file

@ -63,8 +63,6 @@ Everything that is changed is marked (maybe commented) with "Added by MC"
static FRandom pr_botspawn ("BotSpawn");
void InitBotStuff();
//Externs
FCajunMaster bglobal;
@ -321,7 +319,6 @@ bool FCajunMaster::SpawnBot (const char *name, int color)
waitingforspawn[playernumber] = true;
InitBotStuff();
Net_WriteByte (DEM_ADDBOT);
Net_WriteByte (playernumber);
{

View file

@ -68,6 +68,8 @@
#include "p_setup.h"
#include "cmdlib.h"
#include "d_net.h"
#include "v_text.h"
#include "p_lnspec.h"
extern FILE *Logfile;
extern bool insave;
@ -929,6 +931,7 @@ CCMD(nextsecret)
//
//
//-----------------------------------------------------------------------------
CCMD(currentpos)
{
AActor *mo = players[consoleplayer].mo;
@ -936,4 +939,121 @@ CCMD(currentpos)
FIXED2FLOAT(mo->x), FIXED2FLOAT(mo->y), FIXED2FLOAT(mo->z), mo->angle/float(ANGLE_1), FIXED2FLOAT(mo->floorz), mo->Sector->sectornum, mo->Sector->lightlevel);
}
//-----------------------------------------------------------------------------
//
// Print secret info (submitted by Karl Murks)
//
//-----------------------------------------------------------------------------
static void PrintSecretString(const char *string, bool thislevel)
{
const char *colstr = thislevel? TEXTCOLOR_YELLOW : TEXTCOLOR_CYAN;
if (string != NULL)
{
if (*string == '$')
{
if (string[1] == 'S' || string[1] == 's')
{
long secnum = strtol(string+2, (char**)&string, 10);
if (*string == ';') string++;
if (thislevel && secnum >= 0 && secnum < numsectors)
{
if (sectors[secnum].secretsector)
{
if ((sectors[secnum].special & SECRET_MASK)) colstr = TEXTCOLOR_RED;
else colstr = TEXTCOLOR_GREEN;
}
else colstr = TEXTCOLOR_ORANGE;
}
}
else if (string[1] == 'T' || string[1] == 't')
{
long tid = strtol(string+2, (char**)&string, 10);
if (*string == ';') string++;
FActorIterator it(tid);
AActor *actor;
bool foundone = false;
if (thislevel)
{
while ((actor = it.Next()))
{
if (!actor->IsKindOf(PClass::FindClass("SecretTrigger"))) continue;
foundone = true;
break;
}
}
if (foundone) colstr = TEXTCOLOR_YELLOW;
else colstr = TEXTCOLOR_RED;
}
}
FBrokenLines *brok = V_BreakLines(ConFont, screen->GetWidth()*95/100, string);
for (int k = 0; brok[k].Width >= 0; k++)
{
Printf("%s%s\n", colstr, brok[k].Text.GetChars());
}
V_FreeBrokenLines(brok);
}
}
//============================================================================
//
// Print secret hints
//
//============================================================================
CCMD(secret)
{
const char *mapname = argv.argc() < 2? level.mapname : argv[1];
bool thislevel = !stricmp(mapname, level.mapname);
bool foundsome = false;
int lumpno=Wads.CheckNumForName("SECRETS");
if (lumpno < 0) return;
FWadLump lump = Wads.OpenLumpNum(lumpno);
FString maphdr;
maphdr.Format("[%s]", mapname);
FString linebuild;
char readbuffer[1024];
bool inlevel = false;
while (lump.Gets(readbuffer, 1024))
{
if (!inlevel)
{
if (readbuffer[0] == '[')
{
inlevel = !strnicmp(readbuffer, maphdr, maphdr.Len());
if (!foundsome)
{
FString levelname;
level_info_t *info = FindLevelInfo(mapname);
levelname.Format("%s - %s\n", mapname, info->LevelName.GetChars());
size_t llen = levelname.Len() - 1;
for(size_t ii=0; ii<llen; ii++) levelname += '-';
Printf(TEXTCOLOR_YELLOW"%s\n", levelname.GetChars());
foundsome = true;
}
}
continue;
}
else
{
if (readbuffer[0] != '[')
{
linebuild += readbuffer;
if (linebuild.Len() < 1023 || linebuild[1022] == '\n')
{
// line complete so print it.
linebuild.Substitute("\r", "");
linebuild.StripRight(" \t\n");
PrintSecretString(linebuild, thislevel);
linebuild = "";
}
}
else inlevel = false;
}
}
}

View file

@ -94,7 +94,7 @@ extern FBaseCVar *CVars;
extern FConsoleCommand *Commands[FConsoleCommand::HASH_SIZE];
int ConCols, PhysRows;
bool vidactive = false, gotconback = false;
bool vidactive = false;
bool cursoron = false;
int ConBottom, ConScroll, RowAdjust;
int CursorTicker;
@ -232,7 +232,7 @@ CUSTOM_CVAR (Int, msgmidcolor2, 4, CVAR_ARCHIVE)
static void maybedrawnow (bool tick, bool force)
{
// FIXME: Does not work right with hw2d
if (ConsoleDrawing || !gotconback || screen == NULL || screen->IsLocked () || screen->Accel2D)
if (ConsoleDrawing || screen == NULL || screen->IsLocked () || screen->Accel2D || ConFont == NULL)
{
return;
}
@ -297,32 +297,28 @@ void DequeueConsoleText ()
EnqueuedTextTail = &EnqueuedText;
}
void C_InitConback()
{
conback = TexMan.CheckForTexture ("CONBACK", FTexture::TEX_MiscPatch);
if (!conback.isValid())
{
conback = TexMan.GetTexture (gameinfo.titlePage, FTexture::TEX_MiscPatch);
conshade = MAKEARGB(175,0,0,0);
conline = true;
}
else
{
conshade = 0;
conline = false;
}
}
void C_InitConsole (int width, int height, bool ingame)
{
if ( (vidactive = ingame) )
{
if (!gotconback)
{
conback = TexMan.CheckForTexture ("CONBACK", FTexture::TEX_MiscPatch);
if (!conback.isValid())
{
conback = TexMan.GetTexture (gameinfo.titlePage, FTexture::TEX_MiscPatch);
conshade = MAKEARGB(175,0,0,0);
conline = true;
}
else
{
conshade = 0;
conline = false;
}
gotconback = true;
}
}
int cwidth, cheight;
vidactive = ingame;
if (ConFont != NULL)
{
cwidth = ConFont->GetCharWidth ('M');

View file

@ -53,6 +53,7 @@ extern int ConBottom;
// Initialize the console
void C_InitConsole (int width, int height, bool ingame);
void C_DeinitConsole ();
void C_InitConback();
// Adjust the console for a new screen mode
void C_NewModeAdjust (void);

View file

@ -221,7 +221,16 @@ int FBaseCVar::ToInt (UCVarValue value, ECVarType type)
#else
case CVAR_Float: res = (int)value.Float; break;
#endif
case CVAR_String: res = strtol (value.String, NULL, 0); break;
case CVAR_String:
{
if (stricmp (value.String, "true") == 0)
res = 1;
else if (stricmp (value.String, "false") == 0)
res = 0;
else
res = strtol (value.String, NULL, 0);
break;
}
case CVAR_GUID: res = 0; break;
default: res = 0; break;
}
@ -444,7 +453,12 @@ UCVarValue FBaseCVar::FromString (const char *value, ECVarType type)
break;
case CVAR_Int:
ret.Int = strtol (value, NULL, 0);
if (stricmp (value, "true") == 0)
ret.Int = 1;
else if (stricmp (value, "false") == 0)
ret.Int = 0;
else
ret.Int = strtol (value, NULL, 0);
break;
case CVAR_Float:
@ -600,6 +614,11 @@ void FBaseCVar::EnableCallbacks ()
}
}
void FBaseCVar::DisableCallbacks ()
{
m_UseCallback = false;
}
//
// Boolean cvar implementation
//

View file

@ -117,6 +117,7 @@ public:
static void EnableNoSet (); // enable the honoring of CVAR_NOSET
static void EnableCallbacks ();
static void DisableCallbacks ();
static void ResetColors (); // recalc color cvars' indices after screen change
static void ListVars (const char *filter, bool plain);

View file

@ -1211,6 +1211,30 @@ void C_ArchiveAliases (FConfigFile *f)
}
}
void C_ClearAliases ()
{
int bucket;
FConsoleCommand *alias;
for (bucket = 0; bucket < FConsoleCommand::HASH_SIZE; bucket++)
{
alias = Commands[bucket];
while (alias)
{
FConsoleCommand *next = alias->m_Next;
if (alias->IsAlias())
static_cast<FConsoleAlias *>(alias)->SafeDelete();
alias = next;
}
}
}
CCMD(clearaliases)
{
C_ClearAliases();
}
// This is called only by the ini parser.
void C_SetAlias (const char *name, const char *cmd)
{

View file

@ -58,6 +58,7 @@ int C_ExecFile (const char *cmd, bool usePullin);
void C_ArchiveAliases (FConfigFile *f);
void C_SetAlias (const char *name, const char *cmd);
void C_ClearAliases ();
// build a single string out of multiple strings
FString BuildString (int argc, char **argv);

View file

@ -89,6 +89,7 @@ static FCompatOption Options[] =
{ "setslopeoverflow", 0, BCOMPATF_SETSLOPEOVERFLOW },
{ "resetplayerspeed", 0, BCOMPATF_RESETPLAYERSPEED },
{ "vileghosts", 0, BCOMPATF_VILEGHOSTS },
{ "ignoreteleporttags", 0, BCOMPATF_BADTELEPORTERS },
// list copied from g_mapinfo.cpp
{ "shorttex", COMPATF_SHORTTEX, 0 },
@ -141,6 +142,9 @@ void ParseCompatibility()
int i, x;
unsigned int j;
BCompatMap.Clear();
CompatParams.Clear();
// The contents of this file are not cumulative, as it should not
// be present in user-distributed maps.
FScanner sc(Wads.GetNumForFullName("compatibility.txt"));
@ -279,7 +283,6 @@ void CheckCompatibility(MapData *map)
ib_compatflags = 0;
ii_compatparams = -1;
}
else
{
map->GetChecksum(md5.Bytes);

View file

@ -2880,6 +2880,8 @@ void FinishDehPatch ()
// Now that all Dehacked patches have been processed, it's okay to free StateMap.
StateMap.Clear();
StateMap.ShrinkToFit();
TouchedActors.Clear();
TouchedActors.ShrinkToFit();
}
void ModifyDropAmount(AInventory *inv, int dropamount);

View file

@ -227,13 +227,14 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize)
{
sc.MustGetString();
FString wadname = sc.String;
#ifdef _WIN32
#if defined(_WIN32) || defined(__APPLE__) // Turns out Mac OS X is case insensitive.
mIWadNames.Push(wadname);
#else
// check for lowercase, uppercased first letter and full uppercase on Linux etc.
wadname.ToLower();
mIWadNames.Push(wadname);
wadname[0] = toupper(wadname[0]);
wadname.LockBuffer()[0] = toupper(wadname[0]);
wadname.UnlockBuffer();
mIWadNames.Push(wadname);
wadname.ToUpper();
mIWadNames.Push(wadname);
@ -331,7 +332,7 @@ int FIWadManager::CheckIWAD (const char *doomwaddir, WadStuff *wads)
{
FString iwad;
iwad.Format ("%s%s%s", doomwaddir, slash, mIWadNames[i]);
iwad.Format ("%s%s%s", doomwaddir, slash, mIWadNames[i].GetChars());
FixPathSeperator (iwad);
if (FileExists (iwad))
{
@ -547,6 +548,7 @@ int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad,
exit (0);
// zdoom.pk3 must always be the first file loaded and the IWAD second.
wadfiles.Clear();
D_AddFile (wadfiles, zdoom_wad);
if (mIWads[wads[pickwad].Type].preload >= 0)

View file

@ -122,6 +122,7 @@ extern void M_SetDefaultMode ();
extern void R_ExecuteSetViewSize ();
extern void G_NewInit ();
extern void SetupPlayerClasses ();
extern void HUD_InitHud();
const FIWADInfo *D_FindIWAD(TArray<FString> &wadfiles, const char *iwad, const char *basewad);
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
@ -131,6 +132,7 @@ void D_ProcessEvents ();
void G_BuildTiccmd (ticcmd_t* cmd);
void D_DoAdvanceDemo ();
void D_AddWildFile (TArray<FString> &wadfiles, const char *pattern);
void D_LoadWadSettings ();
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
@ -221,6 +223,8 @@ FTexture *Page;
FTexture *Advisory;
bool nospriterename;
FStartupInfo DoomStartupInfo;
FString lastIWAD;
int restart = 0;
cycle_t FrameCycles;
@ -712,10 +716,12 @@ void D_Display ()
}
else
{
unsigned int nowtime = I_FPSTime();
TexMan.UpdateAnimations(nowtime);
R_UpdateSky(nowtime);
switch (gamestate)
{
case GS_FULLCONSOLE:
R_UpdateAnimations(I_FPSTime());
screen->SetBlendingRect(0,0,0,0);
hw2d = screen->Begin2D(false);
C_DrawConsole (false);
@ -780,7 +786,6 @@ void D_Display ()
break;
case GS_INTERMISSION:
R_UpdateAnimations(I_FPSTime());
screen->SetBlendingRect(0,0,0,0);
hw2d = screen->Begin2D(false);
WI_Drawer ();
@ -788,7 +793,6 @@ void D_Display ()
break;
case GS_FINALE:
R_UpdateAnimations(I_FPSTime());
screen->SetBlendingRect(0,0,0,0);
hw2d = screen->Begin2D(false);
F_Drawer ();
@ -796,7 +800,6 @@ void D_Display ()
break;
case GS_DEMOSCREEN:
R_UpdateAnimations(I_FPSTime());
screen->SetBlendingRect(0,0,0,0);
hw2d = screen->Begin2D(false);
D_PageDrawer ();
@ -889,7 +892,7 @@ void D_Display ()
//
// D_ErrorCleanup ()
//
// Cleanup after a recoverable error.
// Cleanup after a recoverable error or a restart
//==========================================================================
void D_ErrorCleanup ()
@ -927,6 +930,7 @@ void D_DoomLoop ()
// Clamp the timer to TICRATE until the playloop has been entered.
r_NoInterpolate = true;
Page = Advisory = NULL;
vid_cursor.Callback();
@ -1563,80 +1567,6 @@ bool ConsiderPatches (const char *arg)
return argc > 0;
}
//==========================================================================
//
// D_LoadWadSettings
//
// Parses any loaded KEYCONF lumps. These are restricted console scripts
// that can only execute the alias, defaultbind, addkeysection,
// addmenukey, weaponsection, and addslotdefault commands.
//
//==========================================================================
void D_LoadWadSettings ()
{
char cmd[4096];
int lump, lastlump = 0;
ParsingKeyConf = true;
while ((lump = Wads.FindLump ("KEYCONF", &lastlump)) != -1)
{
FMemLump data = Wads.ReadLump (lump);
const char *eof = (char *)data.GetMem() + Wads.LumpLength (lump);
const char *conf = (char *)data.GetMem();
while (conf < eof)
{
size_t i;
// Fetch a line to execute
for (i = 0; conf + i < eof && conf[i] != '\n'; ++i)
{
cmd[i] = conf[i];
}
cmd[i] = 0;
conf += i;
if (*conf == '\n')
{
conf++;
}
// Comments begin with //
char *stop = cmd + i - 1;
char *comment = cmd;
int inQuote = 0;
if (*stop == '\r')
*stop-- = 0;
while (comment < stop)
{
if (*comment == '\"')
{
inQuote ^= 1;
}
else if (!inQuote && *comment == '/' && *(comment + 1) == '/')
{
break;
}
comment++;
}
if (comment == cmd)
{ // Comment at line beginning
continue;
}
else if (comment < stop)
{ // Comment in middle of line
*comment = 0;
}
AddCommandString (cmd);
}
}
ParsingKeyConf = false;
}
//==========================================================================
//
// D_MultiExec
@ -1723,7 +1653,8 @@ static FString ParseGameInfo(TArray<FString> &pwads, const char *fn, const char
}
else if (!nextKey.CompareNoCase("NOSPRITERENAME"))
{
nospriterename = true;
sc.MustGetString();
nospriterename = sc.Compare("true");
}
else if (!nextKey.CompareNoCase("STARTUPTITLE"))
{
@ -1809,7 +1740,7 @@ static FString CheckGameInfo(TArray<FString> & pwads)
static void SetMapxxFlag()
{
int lump_name = Wads.CheckNumForName("MAP01", FWadCollection::IWAD_FILENUM);
int lump_name = Wads.CheckNumForName("MAP01", ns_global, FWadCollection::IWAD_FILENUM);
int lump_wad = Wads.CheckNumForFullName("maps/map01.wad", FWadCollection::IWAD_FILENUM);
int lump_map = Wads.CheckNumForFullName("maps/map01.map", FWadCollection::IWAD_FILENUM);
@ -1818,20 +1749,12 @@ static void SetMapxxFlag()
//==========================================================================
//
// D_DoomMain
// Initialize
//
//==========================================================================
void D_DoomMain (void)
static void D_DoomInit()
{
int p, flags;
const char *v;
const char *wad;
DArgs *execFiles;
TArray<FString> pwads;
FString *args;
int argcount;
// Set the FPU precision to 53 significant bits. This is the default
// for Visual C++, but not for GCC, so some slight math variances
// might crop up if we leave it alone.
@ -1859,7 +1782,6 @@ void D_DoomMain (void)
Args->CollectFiles("-playdemo", ".lmp");
Args->CollectFiles("-file", NULL); // anything left goes after -file
PClass::StaticInit ();
atterm (C_DeinitConsole);
gamestate = GS_STARTUP;
@ -1872,30 +1794,16 @@ void D_DoomMain (void)
Printf ("M_LoadDefaults: Load system defaults.\n");
M_LoadDefaults (); // load before initing other systems
// [RH] Make sure zdoom.pk3 is always loaded,
// as it contains magic stuff we need.
}
wad = BaseFileSearch (BASEWAD, NULL, true);
if (wad == NULL)
{
I_FatalError ("Cannot find " BASEWAD);
}
FString basewad = wad;
// Load zdoom.pk3 alone so that we can get access to the internal gameinfos before
// the IWAD is known.
GetCmdLineFiles(pwads);
FString iwad = CheckGameInfo(pwads);
FIWadManager *iwad_man = new FIWadManager;
const FIWADInfo *iwad_info = iwad_man->FindIWAD(allwads, iwad, basewad);
gameinfo.gametype = iwad_info->gametype;
gameinfo.flags = iwad_info->flags;
gameinfo.ConfigName = iwad_info->Configname;
GameConfig->DoGameSetup (gameinfo.ConfigName);
//==========================================================================
//
// AddAutoloadFiles
//
//==========================================================================
static void AddAutoloadFiles(const char *gamesection)
{
if (!(gameinfo.flags & GI_SHAREWARE) && !Args->CheckParm("-noautoload"))
{
FString file;
@ -1905,7 +1813,7 @@ void D_DoomMain (void)
// voices. I never got around to writing the utility to do it, though.
// And I probably never will now. But I know at least one person uses
// it for something else, so this gets to stay here.
wad = BaseFileSearch ("zvox.wad", NULL);
const char *wad = BaseFileSearch ("zvox.wad", NULL);
if (wad)
D_AddFile (allwads, wad);
@ -1932,66 +1840,28 @@ void D_DoomMain (void)
D_AddConfigWads (allwads, file);
// Add IWAD-specific wads
if (iwad_info->Autoname != NULL)
if (gamesection != NULL)
{
file = iwad_info->Autoname;
file = gamesection;
file += ".Autoload";
D_AddConfigWads(allwads, file);
}
}
}
// Run automatically executed files
execFiles = new DArgs;
GameConfig->AddAutoexec (execFiles, gameinfo.ConfigName);
D_MultiExec (execFiles, true);
//==========================================================================
//
// CheckCmdLine
//
//==========================================================================
// Run .cfg files at the start of the command line.
execFiles = Args->GatherFiles ("-exec");
D_MultiExec (execFiles, true);
static void CheckCmdLine()
{
int flags = dmflags;
int p;
const char *v;
C_ExecCmdLineParams (); // [RH] do all +set commands on the command line
CopyFiles(allwads, pwads);
// Since this function will never leave we must delete this array here manually.
pwads.Clear();
pwads.ShrinkToFit();
Printf ("W_Init: Init WADfiles.\n");
Wads.InitMultipleFiles (allwads);
allwads.Clear();
allwads.ShrinkToFit();
SetMapxxFlag();
// [RH] Initialize localizable strings.
GStrings.LoadStrings (false);
V_InitFontColors ();
// [RH] Moved these up here so that we can do most of our
// startup output in a fullscreen console.
CT_Init ();
Printf ("I_Init: Setting up machine state.\n");
I_Init ();
Printf ("V_Init: allocate screen.\n");
V_Init ();
// Base systems have been inited; enable cvar callbacks
FBaseCVar::EnableCallbacks ();
Printf ("S_Init: Setting up sound.\n");
S_Init ();
Printf ("ST_Init: Init startup screen.\n");
StartScreen = FStartupScreen::CreateInstance (R_GuesstimateNumTextures() + 5);
ParseCompatibility();
Printf ("P_Init: Checking cmd-line parameters...\n");
flags = dmflags;
Printf ("Checking cmd-line parameters...\n");
if (Args->CheckParm ("-nomonsters")) flags |= DF_NO_MONSTERS;
if (Args->CheckParm ("-respawn")) flags |= DF_MONSTERS_RESPAWN;
if (Args->CheckParm ("-fast")) flags |= DF_FAST_MONSTERS;
@ -2126,199 +1996,404 @@ void D_DoomMain (void)
temp.Format ("Warp to map %s, Skill %d ", startmap.GetChars(), gameskill + 1);
StartScreen->AppendStatusLine(temp);
}
}
// [RH] Load sound environments
S_ParseReverbDef ();
//==========================================================================
//
// D_DoomMain
//
//==========================================================================
// [RH] Parse through all loaded mapinfo lumps
Printf ("G_ParseMapInfo: Load map definitions.\n");
G_ParseMapInfo (iwad_info->MapInfo);
ReadStatistics();
void D_DoomMain (void)
{
int p;
const char *v;
const char *wad;
DArgs *execFiles;
TArray<FString> pwads;
FString *args;
int argcount;
// [RH] Parse any SNDINFO lumps
Printf ("S_InitData: Load sound definitions.\n");
S_InitData ();
D_DoomInit();
PClass::StaticInit ();
Printf ("Texman.Init: Init texture manager.\n");
TexMan.Init();
// [RH] Make sure zdoom.pk3 is always loaded,
// as it contains magic stuff we need.
// [CW] Parse any TEAMINFO lumps.
Printf ("ParseTeamInfo: Load team definitions.\n");
TeamLibrary.ParseTeamInfo ();
FActorInfo::StaticInit ();
// [GRB] Initialize player class list
SetupPlayerClasses ();
// [RH] Load custom key and weapon settings from WADs
D_LoadWadSettings ();
// [GRB] Check if someone used clearplayerclasses but not addplayerclass
if (PlayerClasses.Size () == 0)
wad = BaseFileSearch (BASEWAD, NULL, true);
if (wad == NULL)
{
I_FatalError ("No player classes defined");
I_FatalError ("Cannot find " BASEWAD);
}
FString basewad = wad;
StartScreen->Progress ();
Printf ("R_Init: Init %s refresh subsystem.\n", gameinfo.ConfigName.GetChars());
StartScreen->LoadingStatus ("Loading graphics", 0x3f);
R_Init ();
// reinit from here
Printf ("DecalLibrary: Load decals.\n");
DecalLibrary.Clear ();
DecalLibrary.ReadAllDecals ();
// [RH] Add any .deh and .bex files on the command line.
// If there are none, try adding any in the config file.
// Note that the command line overrides defaults from the config.
if ((ConsiderPatches("-deh") | ConsiderPatches("-bex")) == 0 &&
gameinfo.gametype == GAME_Doom && GameConfig->SetSection ("Doom.DefaultDehacked"))
do
{
const char *key;
const char *value;
while (GameConfig->NextInSection (key, value))
if (restart)
{
if (stricmp (key, "Path") == 0 && FileExists (value))
{
Printf ("Applying patch %s\n", value);
D_LoadDehFile(value);
}
C_InitConsole(SCREENWIDTH, SCREENHEIGHT, false);
}
}
nospriterename = false;
// Load embedded Dehacked patches
D_LoadDehLumps();
// Load zdoom.pk3 alone so that we can get access to the internal gameinfos before
// the IWAD is known.
// Create replacements for dehacked pickups
FinishDehPatch();
GetCmdLineFiles(pwads);
FString iwad = CheckGameInfo(pwads);
FActorInfo::StaticSetActorNums ();
// The IWAD selection dialogue dpes not show in fullscreen so if the
// restart is initiated without a defined IWAD assume for now that it's not going to change.
if (iwad.Len() == 0) iwad = lastIWAD;
// [RH] User-configurable startup strings. Because BOOM does.
static const char *startupString[5] = {
"STARTUP1", "STARTUP2", "STARTUP3", "STARTUP4", "STARTUP5"
};
for (p = 0; p < 5; ++p)
{
const char *str = GStrings[startupString[p]];
if (str != NULL && str[0] != '\0')
{
Printf ("%s\n", str);
}
}
FIWadManager *iwad_man = new FIWadManager;
const FIWADInfo *iwad_info = iwad_man->FindIWAD(allwads, iwad, basewad);
gameinfo.gametype = iwad_info->gametype;
gameinfo.flags = iwad_info->flags;
gameinfo.ConfigName = iwad_info->Configname;
lastIWAD = iwad;
//Added by MC:
argcount = Args->CheckParmList("-bots", &args);
for (p = 0; p < argcount; ++p)
{
bglobal.getspawned.Push(args[p]);
}
bglobal.spawn_tries = 0;
bglobal.wanted_botnum = bglobal.getspawned.Size();
FBaseCVar::DisableCallbacks();
GameConfig->DoGameSetup (gameinfo.ConfigName);
Printf ("M_Init: Init menus.\n");
M_Init ();
AddAutoloadFiles(iwad_info->Autoname);
Printf ("P_Init: Init Playloop state.\n");
StartScreen->LoadingStatus ("Init game engine", 0x3f);
P_Init ();
// Run automatically executed files
execFiles = new DArgs;
GameConfig->AddAutoexec (execFiles, gameinfo.ConfigName);
D_MultiExec (execFiles, true);
P_SetupWeapons_ntohton();
// Run .cfg files at the start of the command line.
execFiles = Args->GatherFiles ("-exec");
D_MultiExec (execFiles, true);
//SBarInfo support.
SBarInfo::Load();
C_ExecCmdLineParams (); // [RH] do all +set commands on the command line
Printf ("D_CheckNetGame: Checking network game status.\n");
StartScreen->LoadingStatus ("Checking network game status.", 0x3f);
D_CheckNetGame ();
CopyFiles(allwads, pwads);
// [RH] Lock any cvars that should be locked now that we're
// about to begin the game.
FBaseCVar::EnableNoSet ();
// Since this function will never leave we must delete this array here manually.
pwads.Clear();
pwads.ShrinkToFit();
delete iwad_man; // now we won't need this anymore
// [RH] Run any saved commands from the command line or autoexec.cfg now.
gamestate = GS_FULLCONSOLE;
Net_NewMakeTic ();
DThinker::RunThinkers ();
gamestate = GS_STARTUP;
// start the apropriate game based on parms
v = Args->CheckValue ("-record");
if (v)
{
G_RecordDemo (v);
autostart = true;
}
delete StartScreen;
StartScreen = NULL;
if (Args->CheckParm("-norun"))
{
throw CNoRunExit();
}
V_Init2();
v = Args->CheckValue("-playdemo");
if (v != NULL)
{
singledemo = true; // quit after one demo
G_DeferedPlayDemo (v);
D_DoomLoop (); // never returns
}
v = Args->CheckValue ("-timedemo");
if (v)
{
G_TimeDemo (v);
D_DoomLoop (); // never returns
}
Printf ("W_Init: Init WADfiles.\n");
Wads.InitMultipleFiles (allwads);
allwads.Clear();
allwads.ShrinkToFit();
SetMapxxFlag();
v = Args->CheckValue ("-loadgame");
if (v)
{
FString file(v);
FixPathSeperator (file);
DefaultExtension (file, ".zds");
G_LoadGame (file);
}
// [RH] Initialize localizable strings.
GStrings.LoadStrings (false);
if (gameaction != ga_loadgame)
{
if (autostart || netgame)
V_InitFontColors ();
// [RH] Moved these up here so that we can do most of our
// startup output in a fullscreen console.
CT_Init ();
if (!restart)
{
// Do not do any screenwipes when autostarting a game.
if (!Args->CheckParm("-warpwipe"))
Printf ("I_Init: Setting up machine state.\n");
I_Init ();
}
Printf ("V_Init: allocate screen.\n");
V_Init (!!restart);
// Base systems have been inited; enable cvar callbacks
FBaseCVar::EnableCallbacks ();
Printf ("S_Init: Setting up sound.\n");
S_Init ();
Printf ("ST_Init: Init startup screen.\n");
if (!restart) StartScreen = FStartupScreen::CreateInstance (TexMan.GuesstimateNumTextures() + 5);
else StartScreen = new FStartupScreen(0);
ParseCompatibility();
CheckCmdLine();
// [RH] Load sound environments
S_ParseReverbDef ();
// [RH] Parse through all loaded mapinfo lumps
Printf ("G_ParseMapInfo: Load map definitions.\n");
G_ParseMapInfo (iwad_info->MapInfo);
ReadStatistics();
// [RH] Parse any SNDINFO lumps
Printf ("S_InitData: Load sound definitions.\n");
S_InitData ();
Printf ("Texman.Init: Init texture manager.\n");
TexMan.Init();
C_InitConback();
// [CW] Parse any TEAMINFO lumps.
Printf ("ParseTeamInfo: Load team definitions.\n");
TeamLibrary.ParseTeamInfo ();
FActorInfo::StaticInit ();
// [GRB] Initialize player class list
SetupPlayerClasses ();
// [RH] Load custom key and weapon settings from WADs
D_LoadWadSettings ();
// [GRB] Check if someone used clearplayerclasses but not addplayerclass
if (PlayerClasses.Size () == 0)
{
I_FatalError ("No player classes defined");
}
StartScreen->Progress ();
Printf ("R_Init: Init %s refresh subsystem.\n", gameinfo.ConfigName.GetChars());
StartScreen->LoadingStatus ("Loading graphics", 0x3f);
R_Init ();
Printf ("DecalLibrary: Load decals.\n");
DecalLibrary.ReadAllDecals ();
// [RH] Add any .deh and .bex files on the command line.
// If there are none, try adding any in the config file.
// Note that the command line overrides defaults from the config.
if ((ConsiderPatches("-deh") | ConsiderPatches("-bex")) == 0 &&
gameinfo.gametype == GAME_Doom && GameConfig->SetSection ("Doom.DefaultDehacked"))
{
const char *key;
const char *value;
while (GameConfig->NextInSection (key, value))
{
NoWipe = TICRATE;
if (stricmp (key, "Path") == 0 && FileExists (value))
{
Printf ("Applying patch %s\n", value);
D_LoadDehFile(value);
}
}
CheckWarpTransMap (startmap, true);
if (demorecording)
G_BeginRecording (startmap);
G_InitNew (startmap, false);
}
// Load embedded Dehacked patches
D_LoadDehLumps();
// Create replacements for dehacked pickups
FinishDehPatch();
FActorInfo::StaticSetActorNums ();
//Added by MC:
bglobal.getspawned.Clear();
argcount = Args->CheckParmList("-bots", &args);
for (p = 0; p < argcount; ++p)
{
bglobal.getspawned.Push(args[p]);
}
bglobal.spawn_tries = 0;
bglobal.wanted_botnum = bglobal.getspawned.Size();
Printf ("M_Init: Init menus.\n");
M_Init ();
Printf ("P_Init: Init Playloop state.\n");
StartScreen->LoadingStatus ("Init game engine", 0x3f);
AM_StaticInit();
P_Init ();
P_SetupWeapons_ntohton();
//SBarInfo support.
SBarInfo::Load();
HUD_InitHud();
// [RH] User-configurable startup strings. Because BOOM does.
static const char *startupString[5] = {
"STARTUP1", "STARTUP2", "STARTUP3", "STARTUP4", "STARTUP5"
};
for (p = 0; p < 5; ++p)
{
const char *str = GStrings[startupString[p]];
if (str != NULL && str[0] != '\0')
{
Printf ("%s\n", str);
}
}
if (!restart)
{
Printf ("D_CheckNetGame: Checking network game status.\n");
StartScreen->LoadingStatus ("Checking network game status.", 0x3f);
D_CheckNetGame ();
}
// [RH] Lock any cvars that should be locked now that we're
// about to begin the game.
FBaseCVar::EnableNoSet ();
delete iwad_man; // now we won't need this anymore
// [RH] Run any saved commands from the command line or autoexec.cfg now.
gamestate = GS_FULLCONSOLE;
Net_NewMakeTic ();
DThinker::RunThinkers ();
gamestate = GS_STARTUP;
if (!restart)
{
// start the apropriate game based on parms
v = Args->CheckValue ("-record");
if (v)
{
G_RecordDemo (v);
autostart = true;
}
delete StartScreen;
StartScreen = NULL;
if (Args->CheckParm("-norun"))
{
throw CNoRunExit();
}
V_Init2();
v = Args->CheckValue("-playdemo");
if (v != NULL)
{
singledemo = true; // quit after one demo
G_DeferedPlayDemo (v);
D_DoomLoop (); // never returns
}
v = Args->CheckValue ("-timedemo");
if (v)
{
G_TimeDemo (v);
D_DoomLoop (); // never returns
}
v = Args->CheckValue ("-loadgame");
if (v)
{
FString file(v);
FixPathSeperator (file);
DefaultExtension (file, ".zds");
G_LoadGame (file);
}
if (gameaction != ga_loadgame)
{
if (autostart || netgame)
{
// Do not do any screenwipes when autostarting a game.
if (!Args->CheckParm("-warpwipe"))
{
NoWipe = TICRATE;
}
CheckWarpTransMap (startmap, true);
if (demorecording)
G_BeginRecording (startmap);
G_InitNew (startmap, false);
}
else
{
D_StartTitle (); // start up intro loop
}
}
else if (demorecording)
{
G_BeginRecording (NULL);
}
atterm (D_QuitNetGame); // killough
}
else
{
// let the renderer reinitialize some stuff if needed
screen->GameRestart();
// These calls from inside V_Init2 are still necessary
C_NewModeAdjust();
M_InitVideoModesMenu();
D_StartTitle (); // start up intro loop
setmodeneeded = false; // This may be set to true here, but isn't needed for a restart
}
try
{
D_DoomLoop (); // never returns
}
catch (CRestartException &)
{
// Music and sound should be stopped first
S_StopMusic(true);
S_StopAllChannels ();
M_ClearMenus(); // close menu if open
F_EndFinale(); // If an intermission is active, end it now
// clean up game state
ST_Clear();
D_ErrorCleanup ();
P_FreeLevelData();
P_FreeExtraLevelData();
M_SaveDefaults(NULL); // save config before the restart
// delete all data that cannot be left until reinitialization
V_ClearFonts(); // must clear global font pointers
R_DeinitTranslationTables(); // some tables are initialized from outside the translation code.
gameinfo.~gameinfo_t();
new (&gameinfo) gameinfo_t; // Reset gameinfo
S_Shutdown(); // free all channels and delete playlist
C_ClearAliases(); // CCMDs won't be reinitialized so these need to be deleted here
GC::FullGC(); // perform one final garbage collection before deleting the class data
PClass::ClearRuntimeData(); // clear all runtime generated class data
restart++;
}
}
else if (demorecording)
{
G_BeginRecording (NULL);
}
atterm (D_QuitNetGame); // killough
while (1);
}
D_DoomLoop (); // never returns
//==========================================================================
//
// restart the game
//
//==========================================================================
CCMD(restart)
{
// remove command line args that would get in the way during restart
Args->RemoveArgs("-iwad");
Args->RemoveArgs("-deh");
Args->RemoveArgs("-bex");
Args->RemoveArgs("-playdemo");
Args->RemoveArgs("-file");
Args->RemoveArgs("-altdeath");
Args->RemoveArgs("-deathmatch");
Args->RemoveArgs("-skill");
Args->RemoveArgs("-savedir");
Args->RemoveArgs("-xlat");
Args->RemoveArgs("-oldsprites");
if (argv.argc() > 1)
{
for(int i=1;i<argv.argc(); i++)
{
Args->AppendArg(argv[i]);
}
}
// initiate the restart
throw CRestartException();
}
//==========================================================================
@ -2368,6 +2443,14 @@ void FStartupScreen::AppendStatusLine(const char *status)
{
}
void FStartupScreen::Progress(void) {}
void FStartupScreen::NetInit(char const *,int) {}
void FStartupScreen::NetProgress(int) {}
void FStartupScreen::NetMessage(char const *,...) {}
void FStartupScreen::NetDone(void) {}
bool FStartupScreen::NetLoop(bool (*)(void *),void *) { return false; }
//==========================================================================
//
// STAT fps

View file

@ -36,6 +36,12 @@ struct event_t;
// calls all startup code, parses command line options.
// If not overrided by user input, calls N_AdvanceDemo.
//
struct CRestartException
{
char dummy;
};
void D_DoomMain (void);

View file

@ -835,11 +835,9 @@ 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 >= 2193)
{
arc << info.colorset;
}
arc << info.team << info.aimdist << info.color
<< info.skin << info.gender << info.neverswitch
<< info.colorset;
return arc;
}

View file

@ -347,6 +347,16 @@ void FDecalLib::ReadAllDecals ()
int lump, lastlump = 0;
unsigned int i;
for(unsigned i=0;i<Animators.Size(); i++)
{
delete Animators[i];
}
Animators.Clear();
FDecalCombinerAnim::AnimatorList.Clear();
DecalTranslations.Clear();
DecalLibrary.Clear();
while ((lump = Wads.FindLump ("DECALDEF", &lastlump)) != -1)
{
FScanner sc(lump);

View file

@ -540,11 +540,6 @@ void DObject::SerializeUserVars(FArchive &arc)
DWORD count, j;
int *varloc;
if (SaveVersion < 1933)
{
return;
}
symt = &GetClass()->Symbols;
if (arc.IsStoring())

View file

@ -80,6 +80,24 @@ void PClass::StaticInit ()
}
}
void PClass::ClearRuntimeData ()
{
StaticShutdown();
m_RuntimeActors.Clear();
m_Types.Clear();
memset(TypeHash, 0, sizeof(TypeHash));
bShutdown = false;
// Immediately reinitialize the internal classes
FAutoSegIterator probe(CRegHead, CRegTail);
while (*++probe != NULL)
{
((ClassReg *)*probe)->RegisterClass ();
}
}
void PClass::StaticShutdown ()
{
TArray<size_t *> uniqueFPs(64);
@ -105,6 +123,8 @@ void PClass::StaticShutdown ()
uniqueFPs.Push(const_cast<size_t *>(type->FlatPointers));
}
}
type->FlatPointers = NULL;
// For runtime classes, this call will also delete the PClass.
PClass::StaticFreeData (type);
}

View file

@ -125,6 +125,7 @@ struct PClass
static void StaticInit ();
static void StaticShutdown ();
static void StaticFreeData (PClass *type);
static void ClearRuntimeData();
// Per-class information -------------------------------------
FName TypeName; // this class's name

View file

@ -341,6 +341,8 @@ enum
BCOMPATF_SETSLOPEOVERFLOW = 1 << 0, // SetSlope things can overflow
BCOMPATF_RESETPLAYERSPEED = 1 << 1, // Set player speed to 1.0 when changing maps
BCOMPATF_VILEGHOSTS = 1 << 2, // Monsters' radius and height aren't restored properly when resurrected.
BCOMPATF_BADTELEPORTERS = 1 << 3, // Ignore tags on Teleport specials
BCOMPATF_BADPORTALS = 1 << 4, // Restores the old unstable portal behavior
};
// phares 3/20/98:

View file

@ -291,7 +291,11 @@ template<> inline FArchive &operator<< <FFont> (FArchive &arc, FFont* &font)
}
struct FStrifeDialogueNode;
struct FSwitchDef;
struct FDoorAnimation;
template<> FArchive &operator<< (FArchive &arc, FStrifeDialogueNode *&node);
template<> FArchive &operator<< (FArchive &arc, FSwitchDef* &sw);
template<> FArchive &operator<< (FArchive &arc, FDoorAnimation* &da);

View file

@ -180,8 +180,6 @@ wbstartstruct_t wminfo; // parms for world map / intermission
short consistancy[MAXPLAYERS][BACKUPTICS];
BYTE* savebuffer;
#define MAXPLMOVE (forwardmove[1])
@ -240,9 +238,9 @@ CUSTOM_CVAR (Float, turbo, 100.f, 0)
{
self = 10.f;
}
else if (self > 256.f)
else if (self > 255.f)
{
self = 256.f;
self = 255.f;
}
else
{
@ -1906,6 +1904,7 @@ FString G_BuildSaveName (const char *prefix, int slot)
}
CVAR (Int, autosavenum, 0, CVAR_NOSET|CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
static int nextautosave = -1;
CVAR (Int, disableautosave, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR (Int, autosavecount, 4, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
@ -1926,10 +1925,25 @@ void G_DoAutoSave ()
const char *readableTime;
int count = autosavecount != 0 ? autosavecount : 1;
num.Int = (autosavenum + 1) % count;
if (nextautosave == -1)
{
nextautosave = (autosavenum + 1) % count;
}
num.Int = nextautosave;
autosavenum.ForceSet (num, CVAR_Int);
file = G_BuildSaveName ("auto", num.Int);
file = G_BuildSaveName ("auto", nextautosave);
if (!(level.flags2 & LEVEL2_NOAUTOSAVEHINT))
{
nextautosave = (nextautosave + 1) % count;
}
else
{
// This flag can only be used once per level
level.flags2 &= ~LEVEL2_NOAUTOSAVEHINT;
}
readableTime = myasctime ();
strcpy (description, "Autosave ");
@ -2575,6 +2589,7 @@ bool G_CheckDemoStatus (void)
C_RestoreCVars (); // [RH] Restore cvars demo might have changed
M_Free (demobuffer);
demobuffer = NULL;
P_SetupWeapons_ntohton();
demoplayback = false;

View file

@ -85,6 +85,8 @@ void G_AddViewAngle (int yaw);
class AActor;
extern AActor *bodyque[BODYQUESIZE];
extern int bodyqueslot;
class AInventory;
extern const AInventory *SendItemUse, *SendItemDrop;
#endif

View file

@ -462,8 +462,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MacePL1Check)
self->velx = FixedMul(7*FRACUNIT, finecosine[angle]);
self->vely = FixedMul(7*FRACUNIT, finesine[angle]);
#else
double velscale = sqrtf ((float)self->velx * (float)self->velx +
(float)self->vely * (float)self->vely);
double velscale = sqrt ((double)self->velx * (double)self->velx +
(double)self->vely * (double)self->vely);
velscale = 458752 / velscale;
self->velx = (int)(self->velx * velscale);
self->vely = (int)(self->vely * velscale);
@ -1045,6 +1045,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm)
x = self->x + ((pr_storm()&127) - 64) * FRACUNIT;
y = self->y + ((pr_storm()&127) - 64) * FRACUNIT;
mo = Spawn<ARainPillar> (x, y, ONCEILINGZ, ALLOW_REPLACE);
#ifdef _3DFLOORS
// We used bouncecount to store the 3D floor index in A_HideInCeiling
if (!mo) return;
fixed_t newz;
if (self->bouncecount >= 0
&& (unsigned)self->bouncecount < self->Sector->e->XFloor.ffloors.Size())
newz = self->Sector->e->XFloor.ffloors[self->bouncecount]->bottom.plane->ZatPoint(x, y);// - 40 * FRACUNIT;
else
newz = self->Sector->ceilingplane.ZatPoint(x, y);
int moceiling = P_Find3DFloor(NULL, x, y, newz, false, false, newz);
if (moceiling >= 0)
mo->z = newz - mo->height;
#endif
mo->Translation = multiplayer ?
TRANSLATION(TRANSLATION_PlayersExtra,self->special2) : 0;
mo->target = self->target;
@ -1084,6 +1097,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_RainImpact)
DEFINE_ACTION_FUNCTION(AActor, A_HideInCeiling)
{
#ifdef _3DFLOORS
// We use bouncecount to store the 3D floor index
fixed_t foo;
for (unsigned int i=0; i< self->Sector->e->XFloor.ffloors.Size(); i++)
{
F3DFloor * rover = self->Sector->e->XFloor.ffloors[i];
if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
if ((foo = rover->bottom.plane->ZatPoint(self->x, self->y)) >= (self->z + self->height))
{
self->z = foo + 4*FRACUNIT;
self->bouncecount = i;
return;
}
}
self->bouncecount = -1;
#endif
self->z = self->ceilingz + 4*FRACUNIT;
}

View file

@ -76,7 +76,7 @@ struct FHubInfo
};
TArray<FHubInfo> hubdata;
static TArray<FHubInfo> hubdata;
void G_LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs)
{
@ -182,3 +182,8 @@ void G_ReadHubInfo (PNGHandle *png)
G_SerializeHub(arc);
}
}
void G_ClearHubInfo()
{
hubdata.Clear();
}

View file

@ -119,7 +119,6 @@ bool savegamerestore;
extern int mousex, mousey;
extern bool sendpause, sendsave, sendturn180, SendLand;
extern const AInventory *SendItemUse, *SendItemDrop;
void *statcopy; // for statistics driver
@ -309,6 +308,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
bool wantFast;
int i;
G_ClearHubInfo();
if (!savegamerestore)
{
G_ClearSnapshots ();
@ -742,12 +742,7 @@ void G_DoCompleted (void)
{ // Reset world variables for the new hub.
P_ClearACSVars(false);
}
// With hub statistics the time should be per hub.
// Additionally there is a global time counter now so nothing is missed by changing it
//else if (mode == FINISH_NoHub)
{ // Reset time to zero if not entering/staying in a hub.
level.time = 0;
}
level.time = 0;
level.maptime = 0;
}

View file

@ -212,6 +212,7 @@ enum ELevelFlags
LEVEL2_NOSTATISTICS = 0x10000000, // This level should not have statistics collected
LEVEL2_ENDGAME = 0x20000000, // This is an epilogue level that cannot be quit.
LEVEL2_NOAUTOSAVEHINT = 0x40000000, // tell the game that an autosave for this level does not need to be kept
};
@ -514,6 +515,7 @@ void G_UnSnapshotLevel (bool keepPlayers);
struct PNGHandle;
void G_ReadSnapshots (PNGHandle *png);
void G_WriteSnapshots (FILE *file);
void G_ClearHubInfo();
enum ESkillProperty
{

View file

@ -1238,6 +1238,7 @@ MapFlagHandlers[] =
{ "resethealth", MITYPE_SETFLAG2, LEVEL2_RESETHEALTH, 0 },
{ "endofgame", MITYPE_SETFLAG2, LEVEL2_ENDGAME, 0 },
{ "nostatistics", MITYPE_SETFLAG2, LEVEL2_NOSTATISTICS, 0 },
{ "noautosavehint", MITYPE_SETFLAG2, LEVEL2_NOAUTOSAVEHINT, 0 },
{ "unfreezesingleplayerconversations",MITYPE_SETFLAG2, LEVEL2_CONV_SINGLE_UNFREEZE, 0 },
{ "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes
{ "compat_shorttex", MITYPE_COMPATFLAG, COMPATF_SHORTTEX},
@ -1626,7 +1627,13 @@ void FMapInfoParser::ParseEpisodeInfo ()
}
else
{
FEpisode *epi = &AllEpisodes[AllEpisodes.Reserve(1)];
// Only allocate a new entry if this doesn't replace an existing episode.
if (i >= AllEpisodes.Size())
{
i = AllEpisodes.Reserve(1);
}
FEpisode *epi = &AllEpisodes[i];
epi->mEpisodeMap = map;
epi->mEpisodeName = name;
@ -1787,6 +1794,25 @@ void FMapInfoParser::ParseMapInfo (int lump, level_info_t &gamedefaults, level_i
}
//==========================================================================
//
//
//
//==========================================================================
void DeinitIntermissions();
static void ClearMapinfo()
{
wadclusterinfos.Clear();
wadlevelinfos.Clear();
ClearEpisodes();
AllSkills.Clear();
DefaultSkill = -1;
DeinitIntermissions();
level.info = NULL;
}
//==========================================================================
//
// G_ParseMapInfo
@ -1800,7 +1826,8 @@ void G_ParseMapInfo (const char *basemapinfo)
int lump, lastlump = 0;
level_info_t gamedefaults;
atterm(ClearEpisodes);
ClearMapinfo();
atterm(ClearMapinfo);
// Parse the default MAPINFO for the current game. This lump *MUST* come from zdoom.pk3.
if (basemapinfo != NULL)

View file

@ -36,8 +36,6 @@ static FRandom pr_torch ("Torch");
#define TIMEFREEZE_TICS ( 12 * TICRATE )
*/
EXTERN_CVAR (Bool, r_drawfuzz);
IMPLEMENT_CLASS (APowerup)
// Powerup-Giver -------------------------------------------------------------

View file

@ -143,12 +143,21 @@ void AAimingCamera::PostBeginPlay ()
tracer = iterator.Next ();
if (tracer == NULL)
{
Printf ("AimingCamera %d: Can't find thing %d\n", tid, args[3]);
//Printf ("AimingCamera %d: Can't find TID %d\n", tid, args[3]);
}
else
{ // Don't try for a new target upon losing this one.
args[3] = 0;
}
}
void AAimingCamera::Tick ()
{
if (tracer == NULL && args[3] != 0)
{ // Recheck, in case something with this TID was created since the last time.
TActorIterator<AActor> iterator (args[3]);
tracer = iterator.Next ();
}
if (tracer != NULL)
{
angle_t delta;

View file

@ -414,7 +414,7 @@ static void GetWallStuff (side_t *wall, vertex_t *&v1, fixed_t &ldx, fixed_t &ld
static fixed_t Length (fixed_t dx, fixed_t dy)
{
return (fixed_t)sqrtf ((float)dx*(float)dx+(float)dy*(float)dy);
return (fixed_t)sqrt ((double)dx*(double)dx+(double)dy*(double)dy);
}
static side_t *NextWall (const side_t *wall)

View file

@ -16,6 +16,7 @@
#include "a_specialspot.h"
#include "thingdef/thingdef.h"
#include "g_level.h"
#include "g_game.h"
#include "doomstat.h"
static FRandom pr_restore ("RestorePos");
@ -183,6 +184,7 @@ bool P_GiveBody (AActor *actor, int num)
int max;
player_t *player = actor->player;
num = clamp(num, -65536, 65536); // prevent overflows for bad values
if (player != NULL)
{
max = static_cast<APlayerPawn*>(actor)->GetMaxHealth() + player->stamina;
@ -627,7 +629,7 @@ AInventory *AInventory::CreateTossable ()
{
return NULL;
}
if ((ItemFlags & IF_UNDROPPABLE) || Owner == NULL || Amount <= 0)
if ((ItemFlags & (IF_UNDROPPABLE|IF_UNTOSSABLE)) || Owner == NULL || Amount <= 0)
{
return NULL;
}
@ -1033,6 +1035,10 @@ void AInventory::Destroy ()
}
Inventory = NULL;
Super::Destroy ();
// Although contrived it can theoretically happen that these variables still got a pointer to this item
if (SendItemUse == this) SendItemUse = NULL;
if (SendItemDrop == this) SendItemDrop = NULL;
}
//===========================================================================

View file

@ -116,10 +116,10 @@ enum
IF_PICKUPGOOD = 1<<2, // HandlePickup wants normal pickup FX to happen
IF_QUIET = 1<<3, // Don't give feedback when picking up
IF_AUTOACTIVATE = 1<<4, // Automatically activate item on pickup
IF_UNDROPPABLE = 1<<5, // The player cannot manually drop the item
IF_UNDROPPABLE = 1<<5, // Item cannot be removed unless done explicitly with RemoveInventory
IF_INVBAR = 1<<6, // Item appears in the inventory bar
IF_HUBPOWER = 1<<7, // Powerup is kept when moving in a hub
// IF_INTERHUBSTRIP = 1<<8, // Item is removed when travelling between hubs
IF_UNTOSSABLE = 1<<8, // The player cannot manually drop the item
IF_ADDITIVETIME = 1<<9, // when picked up while another item is active, time is added instead of replaced.
IF_ALWAYSPICKUP = 1<<10, // For IF_AUTOACTIVATE, MaxAmount=0 items: Always "pick up", even if it doesn't do anything
IF_FANCYPICKUPSOUND = 1<<11, // Play pickup sound in "surround" mode

View file

@ -55,16 +55,8 @@ void DEarthquake::Serialize (FArchive &arc)
{
Super::Serialize (arc);
arc << m_Spot << m_Intensity << m_Countdown
<< m_TremorRadius << m_DamageRadius;
if (SaveVersion >= 1912)
{
arc << m_QuakeSFX;
}
else
{
m_QuakeSFX = "world/quake";
}
<< m_TremorRadius << m_DamageRadius
<< m_QuakeSFX;
}
//==========================================================================

View file

@ -97,7 +97,6 @@ public:
bool bInSkybox;
bool bAlways;
TObjPtr<ASkyViewpoint> Mate;
fixed_t PlaneAlpha;
};
class AStackPoint : public ASkyViewpoint

View file

@ -69,7 +69,7 @@ void ASkyViewpoint::BeginPlay ()
void ASkyViewpoint::Serialize (FArchive &arc)
{
Super::Serialize (arc);
arc << bInSkybox << bAlways << Mate << PlaneAlpha;
arc << bInSkybox << bAlways << Mate;
}
void ASkyViewpoint::Destroy ()

View file

@ -381,7 +381,9 @@ DBaseStatusBar *CreateCustomStatusBar(int script=0);
// Crosshair stuff ----------------------------------------------------------
void ST_FormatMapName(FString &mapname, const char *mapnamecolor = "");
void ST_LoadCrosshair(bool alwaysload=false);
void ST_Clear();
extern FTexture *CrosshairImage;
#endif /* __SBAR_H__ */

View file

@ -335,6 +335,7 @@ bool FMugShot::SetState(const char *state_name, bool wait_till_done, bool reset)
//
//===========================================================================
CVAR(Bool,st_oldouch,false,CVAR_ARCHIVE)
int FMugShot::UpdateState(player_t *player, StateFlags stateflags)
{
int i;
@ -357,9 +358,10 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags)
}
}
bool ouch = (!st_oldouch && FaceHealth - player->health > ST_MUCHPAIN) || (st_oldouch && player->health - FaceHealth > ST_MUCHPAIN);
if (player->damagecount &&
// Now go in if pain is disabled but we think ouch will be shown (and ouch is not disabled!)
(!(stateflags & DISABLEPAIN) || (((FaceHealth != -1 && FaceHealth - player->health > ST_MUCHPAIN) || bOuchActive) && !(stateflags & DISABLEOUCH))))
(!(stateflags & DISABLEPAIN) || (((FaceHealth != -1 && ouch) || bOuchActive) && !(stateflags & DISABLEOUCH))))
{
int damage_angle = 1;
if (player->attacker && player->attacker != player->mo)
@ -391,7 +393,7 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags)
}
}
bool use_ouch = false;
if (((FaceHealth != -1 && FaceHealth - player->health > ST_MUCHPAIN) || bOuchActive) && !(stateflags & DISABLEOUCH))
if (((FaceHealth != -1 && ouch) || bOuchActive) && !(stateflags & DISABLEOUCH))
{
use_ouch = true;
full_state_name = "ouch.";
@ -418,7 +420,7 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags)
else
{
bool use_ouch = false;
if (((FaceHealth != -1 && player->health - FaceHealth > ST_MUCHPAIN) || bOuchActive) && !(stateflags & DISABLEOUCH))
if (((FaceHealth != -1 && ouch) || bOuchActive) && !(stateflags & DISABLEOUCH))
{
use_ouch = true;
full_state_name = "ouch.";

View file

@ -423,6 +423,8 @@ static void FreeSBarInfoScript()
void SBarInfo::Load()
{
FreeSBarInfoScript();
MugShotStates.Clear();
if(gameinfo.statusbar.IsNotEmpty())
{
int lump = Wads.CheckNumForFullName(gameinfo.statusbar, true);
@ -1153,8 +1155,8 @@ public:
if((offsetflags & SBarInfoCommand::CENTER) == SBarInfoCommand::CENTER)
{
dx -= (texture->GetScaledWidthDouble()/2.0)-texture->LeftOffset;
dy -= (texture->GetScaledHeightDouble()/2.0)-texture->TopOffset;
dx -= (texture->GetScaledWidthDouble()/2.0)-texture->GetScaledLeftOffsetDouble();
dy -= (texture->GetScaledHeightDouble()/2.0)-texture->GetScaledTopOffsetDouble();
}
dx += xOffset;
@ -1188,7 +1190,7 @@ public:
}
if(clearDontDraw)
screen->Clear(static_cast<int>(MAX<double>(dx, dcx)), static_cast<int>(MAX<double>(dy, dcy)), static_cast<int>(dcr), static_cast<int>(dcb), GPalette.BlackIndex, 0);
screen->Clear(static_cast<int>(MAX<double>(dx, dcx)), static_cast<int>(MAX<double>(dy, dcy)), static_cast<int>(MIN<double>(dcr,w+MAX<double>(dx, dcx))), static_cast<int>(MIN<double>(dcb,MAX<double>(dy, dcy)+h)), GPalette.BlackIndex, 0);
else
{
if(alphaMap)

View file

@ -2660,6 +2660,58 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl
////////////////////////////////////////////////////////////////////////////////
class CommandPlayerType : public SBarInfoCommandFlowControl
{
public:
CommandPlayerType(SBarInfo *script) : SBarInfoCommandFlowControl(script)
{
}
void Parse(FScanner &sc, bool fullScreenOffsets)
{
sc.MustGetToken(TK_Identifier);
do
{
bool foundClass = false;
const PClass *cls = PClass::FindClass(sc.String);
if (cls != NULL)
{
foundClass = true;
classes.Push(cls);
}
/*
if(!foundClass)
sc.ScriptError("Unkown PlayerClass '%s'.", sc.String);
*/
if(!sc.CheckToken(','))
break;
}
while(sc.CheckToken(TK_Identifier));
SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets);
}
void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged)
{
SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged);
if(statusBar->CPlayer->cls == NULL)
return; //No class so we can not continue
for(unsigned int i = 0;i < classes.Size();i++)
{
if (statusBar->CPlayer->cls->IsDescendantOf(classes[i]))
{
SetTruth(true, block, statusBar);
return;
}
}
SetTruth(false, block, statusBar);
}
protected:
TArray<const PClass *> classes;
};
////////////////////////////////////////////////////////////////////////////////
class CommandHasWeaponPiece : public SBarInfoCommandFlowControl
{
public:
@ -2730,7 +2782,7 @@ class CommandDrawGem : public SBarInfoCommand
SBarInfoCoordinate drawY = y;
if(wiggle && drawValue != goalValue) // Should only wiggle when the value doesn't equal what is being drawn.
drawY += chainWiggle;
int chainWidth = chainImg->GetWidth();
int chainWidth = chainImg->GetScaledWidth();
int offset = (int) (((double) (chainWidth-leftPadding-rightPadding)/100)*drawValue);
statusBar->DrawGraphic(chainImg, x+(offset%chainSize), drawY, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets());
if(gemImg != NULL)
@ -3082,7 +3134,7 @@ static const char *SBarInfoCommandNames[] =
"drawmugshot", "drawselectedinventory",
"drawinventorybar", "drawbar", "drawgem",
"drawshader", "drawstring", "drawkeybar",
"gamemode", "playerclass", "aspectratio",
"gamemode", "playerclass", "playertype", "aspectratio",
"isselected", "usesammo", "usessecondaryammo",
"hasweaponpiece", "inventorybarnotvisible",
"weaponammo", "ininventory", "alpha",
@ -3095,7 +3147,7 @@ enum SBarInfoCommands
SBARINFO_DRAWMUGSHOT, SBARINFO_DRAWSELECTEDINVENTORY,
SBARINFO_DRAWINVENTORYBAR, SBARINFO_DRAWBAR, SBARINFO_DRAWGEM,
SBARINFO_DRAWSHADER, SBARINFO_DRAWSTRING, SBARINFO_DRAWKEYBAR,
SBARINFO_GAMEMODE, SBARINFO_PLAYERCLASS, SBARINFO_ASPECTRATIO,
SBARINFO_GAMEMODE, SBARINFO_PLAYERCLASS, SBARINFO_PLAYERTYPE, SBARINFO_ASPECTRATIO,
SBARINFO_ISSELECTED, SBARINFO_USESAMMO, SBARINFO_USESSECONDARYAMMO,
SBARINFO_HASWEAPONPIECE, SBARINFO_INVENTORYBARNOTVISIBLE,
SBARINFO_WEAPONAMMO, SBARINFO_ININVENTORY, SBARINFO_ALPHA,
@ -3126,6 +3178,7 @@ SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc)
case SBARINFO_ASPECTRATIO: return new CommandAspectRatio(script);
case SBARINFO_ISSELECTED: return new CommandIsSelected(script);
case SBARINFO_PLAYERCLASS: return new CommandPlayerClass(script);
case SBARINFO_PLAYERTYPE: return new CommandPlayerType(script);
case SBARINFO_HASWEAPONPIECE: return new CommandHasWeaponPiece(script);
case SBARINFO_WEAPONAMMO: return new CommandWeaponAmmo(script);
case SBARINFO_ININVENTORY: return new CommandInInventory(script);

View file

@ -124,16 +124,16 @@ void SetHUDIcon(PClass *cls, FTextureID tex)
//---------------------------------------------------------------------------
static void DrawImageToBox(FTexture * tex, int x, int y, int w, int h, int trans=0xc000)
{
float scale1, scale2;
double scale1, scale2;
if (tex)
{
int texwidth=tex->GetWidth();
int texheight=tex->GetHeight();
if (w<texwidth) scale1=(float)w/texwidth;
if (w<texwidth) scale1=(double)w/texwidth;
else scale1=1.0f;
if (h<texheight) scale2=(float)h/texheight;
if (h<texheight) scale2=(double)h/texheight;
else scale2=1.0f;
if (scale2<scale1) scale1=scale2;
@ -170,11 +170,14 @@ static void DrawHudText(FFont *font, int color, char * text, int x, int y, int t
FTexture *texc = font->GetChar(text[i], &width);
if (texc != NULL)
{
int offset = texc->TopOffset - tex_zero->TopOffset + tex_zero->GetHeight();
double offset = texc->GetScaledTopOffsetDouble()
- tex_zero->GetScaledTopOffsetDouble()
+ tex_zero->GetScaledHeightDouble();
screen->DrawChar(font, color, x, y, text[i],
DTA_KeepRatio, true,
DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, trans,
DTA_LeftOffset, width/2, DTA_TopOffset, offset,
DTA_LeftOffset, width/2, DTA_TopOffsetF, offset,
/*DTA_CenterBottomOffset, 1,*/ TAG_DONE);
}
x += zerowidth;
@ -280,16 +283,42 @@ static void DrawHealth(int health, int x, int y)
//===========================================================================
//
// Draw Armor.
// very similar to drawhealth.
// very similar to drawhealth, but adapted to handle Hexen armor too
//
//===========================================================================
static void DrawArmor(AInventory * armor, int x, int y)
static void DrawArmor(ABasicArmor * barmor, AHexenArmor * harmor, int x, int y)
{
if (armor)
{
int ap=armor->Amount;
int ap = 0;
int bestslot = 4;
if (harmor)
{
int ac = (harmor->Slots[0] + harmor->Slots[1] + harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4]);
ac >>= FRACBITS;
ap += ac;
if (ac)
{
// Find the part of armor that protects the most
bestslot = 0;
for (int i = 1; i < 4; ++i)
{
if (harmor->Slots[i] > harmor->Slots[bestslot])
{
bestslot = i;
}
}
}
}
if (barmor)
{
ap += barmor->Amount;
}
if (ap)
{
// decide on color
int fontcolor =
ap < hud_armor_red ? CR_RED :
@ -298,11 +327,23 @@ static void DrawArmor(AInventory * armor, int x, int y)
CR_BLUE;
if (ap)
// Use the sprite of one of the predefined Hexen armor bonuses.
// This is not a very generic approach, but it is not possible
// to truly create new types of Hexen armor bonus items anyway.
if (harmor && bestslot < 4)
{
DrawImageToBox(TexMan[armor->Icon], x, y, 31, 17);
DrawHudNumber(HudFont, fontcolor, ap, x + 33, y + 17);
char icon[] = "AR_1A0";
switch (bestslot)
{
case 1: icon[3] = '2'; break;
case 2: icon[3] = '3'; break;
case 3: icon[3] = '4'; break;
default: break;
}
DrawImageToBox(TexMan.FindTexture(icon, FTexture::TEX_Sprite), x, y, 31, 17);
}
else if (barmor) DrawImageToBox(TexMan[barmor->Icon], x, y, 31, 17);
DrawHudNumber(HudFont, fontcolor, ap, x + 33, y + 17);
}
}
@ -766,14 +807,11 @@ static void DrawCoordinates(player_t * CPlayer)
// draw the overlay
//
//---------------------------------------------------------------------------
void HUD_InitHud();
void DrawHUD()
{
player_t * CPlayer = StatusBar->CPlayer;
if (HudFont==NULL) HUD_InitHud();
players[consoleplayer].inventorytics = 0;
if (hud_althudscale && SCREENWIDTH>640)
{
@ -815,9 +853,8 @@ void DrawHUD()
DrawFrags(CPlayer, 5, hudheight-70);
}
DrawHealth(CPlayer->health, 5, hudheight-45);
// Yes, that doesn't work properly for Hexen but frankly, I have no
// idea how to make a meaningful value out of Hexen's armor system!
DrawArmor(CPlayer->mo->FindInventory(RUNTIME_CLASS(ABasicArmor)), 5, hudheight-20);
DrawArmor(CPlayer->mo->FindInventory<ABasicArmor>(),
CPlayer->mo->FindInventory<AHexenArmor>(), 5, hudheight-20);
i=DrawKeys(CPlayer, hudwidth-4, hudheight-10);
i=DrawAmmo(CPlayer, hudwidth-5, i);
DrawWeapons(CPlayer, hudwidth-5, i);
@ -830,10 +867,9 @@ void DrawHUD()
}
else
{
FString mapname;
char printstr[256];
int seconds;
cluster_info_t *thiscluster = FindClusterInfo (level.cluster);
bool hub = !!(thiscluster->flags&CLUSTER_HUB);
int length=8*SmallFont->GetCharWidth('0');
int fonth=SmallFont->GetHeight()+1;
int bottom=hudheight-1;
@ -862,8 +898,8 @@ void DrawHUD()
}
}
mysnprintf(printstr, countof(printstr), "%s: %s", level.mapname, level.LevelName.GetChars());
screen->DrawText(SmallFont, hudcolor_titl, 1, hudheight-fonth-1, printstr,
ST_FormatMapName(mapname);
screen->DrawText(SmallFont, hudcolor_titl, 1, hudheight-fonth-1, mapname,
DTA_KeepRatio, true,
DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, TAG_DONE);

View file

@ -95,12 +95,16 @@ CUSTOM_CVAR (Bool, st_scale, true, CVAR_ARCHIVE)
}
}
CVAR (Int, crosshair, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, crosshairforce, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Color, crosshaircolor, 0xff0000, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CVAR (Bool, crosshairhealth, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CVAR (Bool, crosshairscale, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CVAR (Bool, crosshairgrow, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CVAR (Int, crosshair, 0, CVAR_ARCHIVE)
CVAR (Bool, crosshairforce, false, CVAR_ARCHIVE)
CVAR (Color, crosshaircolor, 0xff0000, CVAR_ARCHIVE);
CVAR (Bool, crosshairhealth, true, CVAR_ARCHIVE);
CVAR (Bool, crosshairscale, false, CVAR_ARCHIVE);
CVAR (Bool, crosshairgrow, false, CVAR_ARCHIVE);
CUSTOM_CVAR(Int, am_showmaplabel, 2, CVAR_ARCHIVE)
{
if (self < 0 || self > 2) self = 2;
}
CVAR (Bool, idmypos, false, 0);
@ -118,6 +122,30 @@ BYTE DBaseStatusBar::DamageToAlpha[114] =
230, 231, 232, 233, 234, 235, 235, 236, 237
};
//---------------------------------------------------------------------------
//
// Format the map name, include the map label if wanted
//
//---------------------------------------------------------------------------
void ST_FormatMapName(FString &mapname, const char *mapnamecolor)
{
cluster_info_t *cluster = FindClusterInfo (level.cluster);
bool ishub = (cluster != NULL && (cluster->flags & CLUSTER_HUB));
if (am_showmaplabel == 1 || (am_showmaplabel == 2 && !ishub))
{
mapname << level.mapname << ": ";
}
mapname << mapnamecolor << level.LevelName;
}
//---------------------------------------------------------------------------
//
// Load crosshair definitions
//
//---------------------------------------------------------------------------
void ST_LoadCrosshair(bool alwaysload)
{
int num = 0;
@ -169,6 +197,23 @@ void ST_LoadCrosshair(bool alwaysload)
CrosshairImage = TexMan[TexMan.CheckForTexture(name, FTexture::TEX_MiscPatch)];
}
//---------------------------------------------------------------------------
//
// ST_Clear
//
//---------------------------------------------------------------------------
void ST_Clear()
{
if (StatusBar != NULL)
{
StatusBar->Destroy();
StatusBar = NULL;
}
CrosshairImage = NULL;
CrosshairNum = 0;
}
//---------------------------------------------------------------------------
//
// Constructor
@ -208,6 +253,7 @@ void DBaseStatusBar::Destroy ()
msg->Destroy();
msg = next;
}
Messages = NULL;
Super::Destroy();
}
@ -1270,18 +1316,9 @@ void DBaseStatusBar::Draw (EHudState state)
y -= 8;
}
}
cluster_info_t *cluster = FindClusterInfo (level.cluster);
if (cluster == NULL || !(cluster->flags & CLUSTER_HUB))
{
mysnprintf (line, countof(line), "%s: ", level.mapname);
}
else
{
*line = 0;
}
FString mapname;
mapname.Format("%s%c%c%s", line, TEXTCOLOR_ESCAPE, CR_GREY + 'A', level.LevelName.GetChars());
ST_FormatMapName(mapname, TEXTCOLOR_GREY);
screen->DrawText (SmallFont, highlight,
(SCREENWIDTH - SmallFont->StringWidth (mapname)*CleanXfac)/2, y, mapname,
DTA_CleanNoMove, true, TAG_DONE);

View file

@ -77,7 +77,7 @@ static gameborder_t StrifeBorder =
// Custom GAMEINFO ------------------------------------------------------------
const char* GameInfoBoarders[] =
const char* GameInfoBorders[] =
{
"DoomBorder",
"HereticBorder",
@ -163,6 +163,28 @@ const char* GameInfoBoarders[] =
} \
}
#define GAMEINFOKEY_FONT(key, variable) \
else if(nextKey.CompareNoCase(variable) == 0) \
{ \
sc.MustGetToken(TK_StringConst); \
gameinfo.key.fontname = sc.String; \
if (sc.CheckToken(',')) { \
sc.MustGetToken(TK_StringConst); \
gameinfo.key.color = sc.String; \
} else { \
gameinfo.key.color = NAME_None; \
} \
}
#define GAMEINFOKEY_PATCH(key, variable) \
else if(nextKey.CompareNoCase(variable) == 0) \
{ \
sc.MustGetToken(TK_StringConst); \
gameinfo.key.fontname = sc.String; \
gameinfo.key.color = NAME_Null; \
}
void FMapInfoParser::ParseGameInfo()
{
sc.MustGetToken('{');
@ -197,7 +219,7 @@ void FMapInfoParser::ParseGameInfo()
{
if(sc.CheckToken(TK_Identifier))
{
switch(sc.MustMatchString(GameInfoBoarders))
switch(sc.MustMatchString(GameInfoBorders))
{
default:
gameinfo.border = &DoomBorder;
@ -247,6 +269,17 @@ void FMapInfoParser::ParseGameInfo()
gameinfo.ArmorIcon2[8] = 0;
}
}
else if(nextKey.CompareNoCase("maparrow") == 0)
{
sc.MustGetToken(TK_StringConst);
gameinfo.mMapArrow = sc.String;
if (sc.CheckToken(','))
{
sc.MustGetToken(TK_StringConst);
gameinfo.mCheatMapArrow = sc.String;
}
else gameinfo.mCheatMapArrow = "";
}
// Insert valid keys here.
GAMEINFOKEY_CSTRING(titlePage, "titlePage", 8)
GAMEINFOKEY_STRINGARRAY(creditPages, "creditPage", 8)
@ -300,6 +333,11 @@ void FMapInfoParser::ParseGameInfo()
GAMEINFOKEY_INT(TextScreenX, "textscreenx")
GAMEINFOKEY_INT(TextScreenY, "textscreeny")
GAMEINFOKEY_STRING(DefaultEndSequence, "defaultendsequence")
GAMEINFOKEY_FONT(mStatscreenMapNameFont, "statscreen_mapnamefont")
GAMEINFOKEY_FONT(mStatscreenFinishedFont, "statscreen_finishedfont")
GAMEINFOKEY_FONT(mStatscreenEnteringFont, "statscreen_enteringfont")
GAMEINFOKEY_PATCH(mStatscreenFinishedFont, "statscreen_finishedpatch")
GAMEINFOKEY_PATCH(mStatscreenEnteringFont, "statscreen_enteringpatch")
else
{

View file

@ -46,7 +46,7 @@
#define GI_COMPATSTAIRS 0x00000020 // same for stairbuilding
#define GI_COMPATPOLY1 0x00000040 // Hexen's MAP36 needs old polyobject drawing
#define GI_COMPATPOLY2 0x00000080 // so does HEXDD's MAP47
#define GI_NOTEXTCOLOR 0x00000100
#define GI_NOTEXTCOLOR 0x00000100 // Chex Quest 3 would have everything green
#include "gametype.h"
@ -66,6 +66,12 @@ struct gameborder_t
char br[8];
};
struct FGIFont
{
FName fontname;
FName color;
};
struct gameinfo_t
{
int flags;
@ -129,6 +135,10 @@ struct gameinfo_t
int TextScreenX;
int TextScreenY;
FName DefaultEndSequence;
FString mMapArrow, mCheatMapArrow;
FGIFont mStatscreenMapNameFont;
FGIFont mStatscreenFinishedFont;
FGIFont mStatscreenEnteringFont;
const char *GetFinalePage(unsigned int num) const;
};

View file

@ -153,8 +153,8 @@ static int LS_Sector_SetPlaneReflection (line_t *ln, AActor *it, bool backSide,
while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0)
{
sector_t * s = &sectors[secnum];
if (s->floorplane.a==0 && s->floorplane.b==0) s->floor_reflect = arg1/255.f;
if (s->ceilingplane.a==0 && s->ceilingplane.b==0) sectors[secnum].ceiling_reflect = arg2/255.f;
if (s->floorplane.a==0 && s->floorplane.b==0) s->reflect[sector_t::floor] = arg1/255.f;
if (s->ceilingplane.a==0 && s->ceilingplane.b==0) sectors[secnum].reflect[sector_t::ceiling] = arg2/255.f;
}
return true;

View file

@ -23,30 +23,28 @@ struct GLRenderSettings
extern GLRenderSettings glset;
#include "r_defs.h"
#include "a_sharedglobal.h"
void gl_RecalcVertexHeights(vertex_t * v);
FTextureID gl_GetSpriteFrame(unsigned sprite, int frame, int rot, angle_t ang, bool *mirror);
class AStackPoint;
struct GLSectorStackPortal;
struct FPortal
{
TArray<vertex_t *> Shape; // forms the smallest convex outline around the portal area
TArray<angle_t> ClipAngles;
fixed_t xDisplacement;
fixed_t yDisplacement;
int plane;
AStackPoint *origin;
GLSectorStackPortal *glportal; // for quick access to the render data. This is only valid during BSP traversal!
int PointOnShapeLineSide(fixed_t x, fixed_t y, int shapeindex);
void AddVertexToShape(vertex_t *vertex);
void AddSectorToPortal(sector_t *sector);
void UpdateClipAngles();
GLSectorStackPortal *GetGLPortal();
};
extern TArray<FPortal> portals;
extern TArray<FPortal *> portals;
extern TArray<BYTE> currentmapsection;
void gl_InitPortals();
void gl_BuildPortalCoverage(FPortalCoverage *coverage, subsector_t *subsector, FPortal *portal);
#endif

View file

@ -57,25 +57,48 @@
#include "gl/data/gl_data.h"
#include "gl/data/gl_vertexbuffer.h"
#include "gl/scene/gl_clipper.h"
#include "gl/scene/gl_portal.h"
#include "gl/dynlights/gl_dynlight.h"
#include "gl/dynlights/gl_glow.h"
#include "gl/utility/gl_clock.h"
#include "gl/gl_functions.h"
TArray<FPortal> portals;
//==========================================================================
//
//
//
//==========================================================================
int FPortal::PointOnShapeLineSide(fixed_t x, fixed_t y, int shapeindex)
struct FPortalID
{
int shapeindex2 = (shapeindex+1)%Shape.Size();
fixed_t mXDisplacement;
fixed_t mYDisplacement;
return DMulScale32(y - Shape[shapeindex]->y, Shape[shapeindex2]->x - Shape[shapeindex]->x,
Shape[shapeindex]->x - x, Shape[shapeindex2]->y - Shape[shapeindex]->y);
// for the hash code
operator intptr_t() const { return (mXDisplacement >> 8) + (mYDisplacement << 8); }
bool operator != (const FPortalID &other) const
{
return mXDisplacement != other.mXDisplacement ||
mYDisplacement != other.mYDisplacement;
}
};
struct FPortalSector
{
sector_t *mSub;
int mPlane;
};
typedef TArray<FPortalSector> FPortalSectors;
typedef TMap<FPortalID, FPortalSectors> FPortalMap;
TArray<FPortal *> portals;
//==========================================================================
//
//
//
//==========================================================================
GLSectorStackPortal *FPortal::GetGLPortal()
{
if (glportal == NULL) glportal = new GLSectorStackPortal(this);
return glportal;
}
//==========================================================================
@ -84,123 +107,241 @@ int FPortal::PointOnShapeLineSide(fixed_t x, fixed_t y, int shapeindex)
//
//==========================================================================
void FPortal::AddVertexToShape(vertex_t *vertex)
struct FCoverageVertex
{
for(unsigned i=0;i<Shape.Size(); i++)
fixed_t x, y;
bool operator !=(FCoverageVertex &other)
{
if (vertex->x == Shape[i]->x && vertex->y == Shape[i]->y) return;
return x != other.x || y != other.y;
}
};
struct FCoverageLine
{
FCoverageVertex v[2];
};
struct FCoverageBuilder
{
subsector_t *target;
FPortal *portal;
TArray<int> collect;
FCoverageVertex center;
//==========================================================================
//
//
//
//==========================================================================
FCoverageBuilder(subsector_t *sub, FPortal *port)
{
target = sub;
portal = port;
}
if (Shape.Size() < 2)
//==========================================================================
//
// GetIntersection
//
// adapted from P_InterceptVector
//
//==========================================================================
bool GetIntersection(FCoverageVertex *v1, FCoverageVertex *v2, node_t *bsp, FCoverageVertex *v)
{
Shape.Push(vertex);
double frac;
double num;
double den;
double v2x = (double)v1->x;
double v2y = (double)v1->y;
double v2dx = (double)(v2->x - v1->x);
double v2dy = (double)(v2->y - v1->y);
double v1x = (double)bsp->x;
double v1y = (double)bsp->y;
double v1dx = (double)bsp->dx;
double v1dy = (double)bsp->dy;
den = v1dy*v2dx - v1dx*v2dy;
if (den == 0)
return false; // parallel
num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx;
frac = num / den;
if (frac < 0. || frac > 1.) return false;
v->x = xs_RoundToInt(v2x + frac * v2dx);
v->y = xs_RoundToInt(v2y + frac * v2dy);
return true;
}
else if (Shape.Size() == 2)
{
// Special case: We need to check if the vertex is on an extension of the line between the first two vertices.
int pos = PointOnShapeLineSide(vertex->x, vertex->y, 0);
if (pos == 0)
{
fixed_t distv1 = P_AproxDistance(vertex->x - Shape[0]->x, vertex->y - Shape[0]->y);
fixed_t distv2 = P_AproxDistance(vertex->x - Shape[1]->x, vertex->y - Shape[1]->y);
fixed_t distvv = P_AproxDistance(Shape[0]->x - Shape[1]->x, Shape[0]->y - Shape[1]->y);
//==========================================================================
//
//
//
//==========================================================================
if (distv1 > distvv)
{
Shape[1] = vertex;
}
else if (distv2 > distvv)
{
Shape[0] = vertex;
}
return;
}
else if (pos > 0)
{
Shape.Insert(1, vertex);
}
else
{
Shape.Push(vertex);
}
double PartitionDistance(FCoverageVertex *vt, node_t *node)
{
return fabs(double(-node->dy) * (vt->x - node->x) + double(node->dx) * (vt->y - node->y)) / node->len;
}
else
{
for(unsigned i=0; i<Shape.Size(); i++)
{
int startlinepos = PointOnShapeLineSide(vertex->x, vertex->y, i);
if (startlinepos >= 0)
{
int previouslinepos = PointOnShapeLineSide(vertex->x, vertex->y, (i+Shape.Size()-1)%Shape.Size());
if (previouslinepos < 0) // we found the first line for which the vertex lies in front
//==========================================================================
//
//
//
//==========================================================================
int PointOnSide(FCoverageVertex *vt, node_t *node)
{
return R_PointOnSide(vt->x, vt->y, node);
}
//==========================================================================
//
// adapted from polyobject splitter
//
//==========================================================================
void CollectNode(void *node, TArray<FCoverageVertex> &shape)
{
static TArray<FCoverageLine> lists[2];
const double COVERAGE_EPSILON = 6.; // same epsilon as the node builder
if (!((size_t)node & 1)) // Keep going until found a subsector
{
node_t *bsp = (node_t *)node;
int centerside = R_PointOnSide(center.x, center.y, bsp);
lists[0].Clear();
lists[1].Clear();
for(unsigned i=0;i<shape.Size(); i++)
{
FCoverageVertex *v1 = &shape[i];
FCoverageVertex *v2 = &shape[(i+1) % shape.Size()];
FCoverageLine vl = { *v1, *v2 };
double dist_v1 = PartitionDistance(v1, bsp);
double dist_v2 = PartitionDistance(v2, bsp);
if(dist_v1 <= COVERAGE_EPSILON)
{
unsigned int nextpoint = i;
do
if (dist_v2 <= COVERAGE_EPSILON)
{
nextpoint = (nextpoint+1) % Shape.Size();
}
while (PointOnShapeLineSide(vertex->x, vertex->y, nextpoint) >= 0);
int removecount = (nextpoint - i + Shape.Size()) % Shape.Size() - 1;
if (removecount == 0)
{
if (startlinepos > 0)
{
Shape.Insert(i+1, vertex);
}
}
else if (nextpoint > i || nextpoint == 0)
{
// The easy case: It doesn't wrap around
Shape.Delete(i+1, removecount-1);
Shape[i+1] = vertex;
lists[centerside].Push(vl);
}
else
{
// It does wrap around.
Shape.Delete(i+1, removecount);
Shape.Delete(1, nextpoint-1);
Shape[0] = vertex;
int side = PointOnSide(v2, bsp);
lists[side].Push(vl);
}
}
else if (dist_v2 <= COVERAGE_EPSILON)
{
int side = PointOnSide(v1, bsp);
lists[side].Push(vl);
}
else
{
int side1 = PointOnSide(v1, bsp);
int side2 = PointOnSide(v2, bsp);
if(side1 != side2)
{
// if the partition line crosses this seg, we must split it.
FCoverageVertex vert;
if (GetIntersection(v1, v2, bsp, &vert))
{
lists[0].Push(vl);
lists[1].Push(vl);
lists[side1].Last().v[1] = vert;
lists[side2].Last().v[0] = vert;
}
else
{
// should never happen
lists[side1].Push(vl);
}
}
else
{
// both points on the same side.
lists[side1].Push(vl);
}
return;
}
}
if (lists[1].Size() == 0)
{
CollectNode(bsp->children[0], shape);
}
else if (lists[0].Size() == 0)
{
CollectNode(bsp->children[1], shape);
}
else
{
// copy the static arrays into local ones
TArray<FCoverageVertex> locallists[2];
for(int l=0;l<2;l++)
{
for (unsigned i=0;i<lists[l].Size(); i++)
{
locallists[l].Push(lists[l][i].v[0]);
unsigned i1= (i+1)%lists[l].Size();
if (lists[l][i1].v[0] != lists[l][i].v[1])
{
locallists[l].Push(lists[l][i].v[1]);
}
}
}
CollectNode(bsp->children[0], locallists[0]);
CollectNode(bsp->children[1], locallists[1]);
}
}
else
{
// we reached a subsector so we can link the node with this subsector
subsector_t *sub = (subsector_t *)((BYTE *)node - 1);
collect.Push(int(sub-subsectors));
}
}
}
};
//==========================================================================
//
//
// Calculate portal coverage for a single subsector
//
//==========================================================================
void FPortal::AddSectorToPortal(sector_t *sector)
void gl_BuildPortalCoverage(FPortalCoverage *coverage, subsector_t *subsector, FPortal *portal)
{
for(int i=0; i<sector->linecount; i++)
{
AddVertexToShape(sector->lines[i]->v1);
// This is necessary to handle unclosed sectors
AddVertexToShape(sector->lines[i]->v2);
}
}
TArray<FCoverageVertex> shape;
double centerx=0, centery=0;
//==========================================================================
//
//
//
//==========================================================================
void FPortal::UpdateClipAngles()
{
for(unsigned int i=0; i<Shape.Size(); i++)
shape.Resize(subsector->numlines);
for(unsigned i=0; i<subsector->numlines; i++)
{
ClipAngles[i] = R_PointToPseudoAngle(viewx, viewy, Shape[i]->x, Shape[i]->y);
centerx += (shape[i].x = subsector->firstline[i].v1->x + portal->xDisplacement);
centery += (shape[i].y = subsector->firstline[i].v1->y + portal->yDisplacement);
}
FCoverageBuilder build(subsector, portal);
build.center.x = xs_CRoundToInt(centerx / subsector->numlines);
build.center.y = xs_CRoundToInt(centery / subsector->numlines);
build.CollectNode(nodes + numnodes - 1, shape);
coverage->subsectors = new DWORD[build.collect.Size()];
coverage->sscount = build.collect.Size();
memcpy(coverage->subsectors, &build.collect[0], build.collect.Size() * sizeof(DWORD));
}
//==========================================================================
@ -209,68 +350,124 @@ void FPortal::UpdateClipAngles()
//
//==========================================================================
void gl_InitPortals()
static void CollectPortalSectors(FPortalMap &collection)
{
TThinkerIterator<AStackPoint> it;
AStackPoint *pt;
portals.Clear();
while ((pt = it.Next()))
for (int i=0;i<numsectors;i++)
{
FPortal *portal = NULL;
int plane;
pt->special1 = -1;
for(int i=0;i<numsectors;i++)
sector_t *sec = &sectors[i];
if (sec->CeilingSkyBox != NULL && sec->CeilingSkyBox->bAlways && sec->CeilingSkyBox->Mate != NULL)
{
if (sectors[i].linecount == 0)
{
continue;
}
else if (sectors[i].FloorSkyBox == pt)
{
plane = 1;
}
else if (sectors[i].CeilingSkyBox == pt)
{
plane = 2;
}
else continue;
FPortalID id = { sec->CeilingSkyBox->x - sec->CeilingSkyBox->Mate->x,
sec->CeilingSkyBox->y - sec->CeilingSkyBox->Mate->y};
// we only process portals that actually are in use.
if (portal == NULL)
{
pt->special1 = portals.Size(); // Link portal thing to render data
portal = &portals[portals.Reserve(1)];
portal->origin = pt;
portal->plane = 0;
portal->xDisplacement = pt->x - pt->Mate->x;
portal->yDisplacement = pt->y - pt->Mate->y;
}
portal->AddSectorToPortal(&sectors[i]);
portal->plane|=plane;
FPortalSectors &sss = collection[id];
FPortalSector ss = { sec, sector_t::ceiling };
sss.Push(ss);
}
if (portal != NULL)
if (sec->FloorSkyBox != NULL && sec->FloorSkyBox->bAlways && sec->FloorSkyBox->Mate != NULL)
{
// if the first vertex is duplicated at the end it'll save time in a time critical function
// because that code does not need to check for wraparounds anymire.
portal->Shape.Resize(portal->Shape.Size()+1);
portal->Shape[portal->Shape.Size()-1] = portal->Shape[0];
portal->Shape.ShrinkToFit();
portal->ClipAngles.Resize(portal->Shape.Size());
FPortalID id = { sec->FloorSkyBox->x - sec->FloorSkyBox->Mate->x,
sec->FloorSkyBox->y - sec->FloorSkyBox->Mate->y };
FPortalSectors &sss = collection[id];
FPortalSector ss = { sec, sector_t::floor };
sss.Push(ss);
}
}
}
void gl_InitPortals()
{
FPortalMap collection;
if (numnodes == 0) return;
for(int i=0;i<numnodes;i++)
{
node_t *no = &nodes[i];
double fdx = (double)no->dx;
double fdy = (double)no->dy;
no->len = (float)sqrt(fdx * fdx + fdy * fdy);
}
CollectPortalSectors(collection);
portals.Clear();
FPortalMap::Iterator it(collection);
FPortalMap::Pair *pair;
int c = 0;
int planeflags = 0;
while (it.NextPair(pair))
{
for(unsigned i=0;i<pair->Value.Size(); i++)
{
if (pair->Value[i].mPlane == sector_t::floor) planeflags |= 1;
else if (pair->Value[i].mPlane == sector_t::ceiling) planeflags |= 2;
}
for (int i=1;i<=2;i<<=1)
{
// For now, add separate portals for floor and ceiling. They can be merged once
// proper plane clipping is in.
if (planeflags & i)
{
FPortal *portal = new FPortal;
portal->xDisplacement = pair->Key.mXDisplacement;
portal->yDisplacement = pair->Key.mYDisplacement;
portal->plane = (i==1? sector_t::floor : sector_t::ceiling); /**/
portals.Push(portal);
for(unsigned j=0;j<pair->Value.Size(); j++)
{
sector_t *sec = pair->Value[j].mSub;
int plane = pair->Value[j].mPlane;
if (portal->plane == plane)
{
for(int k=0;k<sec->subsectorcount; k++)
{
subsector_t *sub = sec->subsectors[k];
gl_BuildPortalCoverage(&sub->portalcoverage[plane], sub, portal);
}
sec->portals[plane] = portal;
}
}
}
}
}
}
CCMD(dumpportals)
{
for(unsigned i=0;i<portals.Size(); i++)
{
Printf("Portal #%d, plane %d, stackpoint at (%f,%f), displacement = (%f,%f)\n", i, portals[i].plane, portals[i].origin->x/65536., portals[i].origin->y/65536.,
portals[i].origin->x/65536. - portals[i].origin->Mate->x/65536., portals[i].origin->y/65536. - portals[i].origin->Mate->y/65536.);
for (unsigned j=0;j<portals[i].Shape.Size(); j++)
double xdisp = portals[i]->xDisplacement/65536.;
double ydisp = portals[i]->yDisplacement/65536.;
Printf(PRINT_LOG, "Portal #%d, %s, displacement = (%f,%f)\n", i, portals[i]->plane==0? "floor":"ceiling",
xdisp, ydisp);
Printf(PRINT_LOG, "Coverage:\n");
for(int j=0;j<numsubsectors;j++)
{
Printf("\t(%f,%f)\n", (portals[i].Shape[j]->x + portals[i].xDisplacement)/65536., (portals[i].Shape[j]->y + portals[i].yDisplacement)/65536.);
subsector_t *sub = &subsectors[j];
FPortal *port = sub->render_sector->portals[portals[i]->plane];
if (port == portals[i])
{
Printf(PRINT_LOG, "\tSubsector %d (%d):\n\t\t", j, sub->render_sector->sectornum);
for(unsigned k = 0;k< sub->numlines; k++)
{
Printf(PRINT_LOG, "(%.3f,%.3f), ", sub->firstline[k].v1->x/65536. + xdisp, sub->firstline[k].v1->y/65536. + ydisp);
}
Printf(PRINT_LOG, "\n\t\tCovered by subsectors:\n");
FPortalCoverage *cov = &sub->portalcoverage[portals[i]->plane];
for(int l = 0;l< cov->sscount; l++)
{
subsector_t *csub = &subsectors[cov->subsectors[l]];
Printf(PRINT_LOG, "\t\t\t%5d (%4d): ", cov->subsectors[l], csub->render_sector->sectornum);
for(unsigned m = 0;m< csub->numlines; m++)
{
Printf(PRINT_LOG, "(%.3f,%.3f), ", csub->firstline[m].v1->x/65536., csub->firstline[m].v1->y/65536.);
}
Printf(PRINT_LOG, "\n");
}
}
}
}
}

View file

@ -103,6 +103,153 @@ void gl_InitSegs()
}
}
//==========================================================================
//
//
//
//==========================================================================
static void DoSetMapSection(subsector_t *sub, int num)
{
sub->mapsection = num;
for(DWORD i=0;i<sub->numlines;i++)
{
seg_t * seg = sub->firstline + i;
if (seg->PartnerSeg)
{
subsector_t * sub2 = seg->PartnerSeg->Subsector();
if (sub2->mapsection != num)
{
assert(sub2->mapsection == 0);
DoSetMapSection(sub2, num);
}
}
}
}
//==========================================================================
//
// Merge sections. This is needed in case the map contains errors
// like overlapping lines resulting in abnormal subsectors.
//
// This function ensures that any vertex position can only be in one section.
//
//==========================================================================
struct cvertex_t
{
fixed_t x, y;
operator int () const { return ((x>>16)&0xffff) | y; }
bool operator!= (const cvertex_t &other) const { return x != other.x || y != other.y; }
cvertex_t& operator =(const vertex_t *v) { x = v->x; y = v->y; return *this; }
};
typedef TMap<cvertex_t, int> FSectionVertexMap;
static int MergeMapSections(int num)
{
FSectionVertexMap vmap;
FSectionVertexMap::Pair *pair;
TArray<int> sectmap;
TArray<bool> sectvalid;
sectmap.Resize(num);
sectvalid.Resize(num);
for(int i=0;i<num;i++)
{
sectmap[i] = -1;
sectvalid[i] = true;
}
int mergecount = 1;
cvertex_t vt;
// first step: Set mapsection for all vertex positions.
for(DWORD i=0;i<numsegs;i++)
{
seg_t * seg = &segs[i];
int section = seg->Subsector()->mapsection;
for(int j=0;j<2;j++)
{
vt = j==0? seg->v1:seg->v2;
vmap[vt] = section;
}
}
// second step: Check if any seg references more than one mapsection, either by subsector or by vertex
for(DWORD i=0;i<numsegs;i++)
{
seg_t * seg = &segs[i];
int section = seg->Subsector()->mapsection;
for(int j=0;j<2;j++)
{
vt = j==0? seg->v1:seg->v2;
int vsection = vmap[vt];
if (vsection != section)
{
// These 2 sections should be merged
for(int k=0;k<numsubsectors;k++)
{
if (subsectors[k].mapsection == vsection) subsectors[k].mapsection = section;
}
FSectionVertexMap::Iterator it(vmap);
while (it.NextPair(pair))
{
if (pair->Value == vsection) pair->Value = section;
}
sectvalid[vsection-1] = false;
}
}
}
for(int i=0;i<num;i++)
{
if (sectvalid[i]) sectmap[i] = mergecount++;
}
for(int i=0;i<numsubsectors;i++)
{
subsectors[i].mapsection = sectmap[subsectors[i].mapsection-1];
assert(subsectors[i].mapsection!=-1);
}
return mergecount-1;
}
//==========================================================================
//
//
//
//==========================================================================
static void SetMapSections()
{
bool set;
int num = 0;
do
{
set = false;
for(int i=0; i<numsubsectors; i++)
{
if (subsectors[i].mapsection == 0)
{
num++;
DoSetMapSection(&subsectors[i], num);
set = true;
break;
}
}
}
while (set);
num = MergeMapSections(num);
currentmapsection.Resize(1 + num/8);
#ifdef DEBUG
Printf("%d map sections found\n", num);
#endif
}
//==========================================================================
//
// prepare subsectors for GL rendering
@ -112,20 +259,6 @@ void gl_InitSegs()
//
//==========================================================================
inline void M_ClearBox (fixed_t *box)
{
box[BOXTOP] = box[BOXRIGHT] = INT_MIN;
box[BOXBOTTOM] = box[BOXLEFT] = INT_MAX;
}
inline void M_AddToBox(fixed_t* box,fixed_t x,fixed_t y)
{
if (x<box[BOXLEFT]) box[BOXLEFT] = x;
if (x>box[BOXRIGHT]) box[BOXRIGHT] = x;
if (y<box[BOXBOTTOM]) box[BOXBOTTOM] = y;
if (y>box[BOXTOP]) box[BOXTOP] = y;
}
static void SpreadHackedFlag(subsector_t * sub)
{
// The subsector pointer hasn't been set yet!
@ -147,27 +280,18 @@ static void SpreadHackedFlag(subsector_t * sub)
}
//==========================================================================
//
//
//
//==========================================================================
static void PrepareSectorData()
{
int i;
size_t /*ii,*/ jj;
TArray<subsector_t *> undetermined;
subsector_t * ss;
// look up sector number for each subsector
for (i = 0; i < numsubsectors; i++)
{
ss = &subsectors[i];
seg_t *seg = ss->firstline;
M_ClearBox(ss->bbox);
for(jj=0; jj<ss->numlines; jj++)
{
M_AddToBox(ss->bbox,seg->v1->x, seg->v1->y);
seg++;
}
}
// now group the subsectors by sector
subsector_t ** subsectorbuffer = new subsector_t * [numsubsectors];
@ -208,6 +332,7 @@ static void PrepareSectorData()
}
}
}
SetMapSections();
}
//==========================================================================
@ -216,6 +341,7 @@ static void PrepareSectorData()
// - This will be used to lower the floor of such sectors by one map unit
//
//==========================================================================
static void PrepareTransparentDoors(sector_t * sector)
{
bool solidwall=false;
@ -300,12 +426,12 @@ static void PrepareTransparentDoors(sector_t * sector)
}
}
//==========================================================================
//
//
//
//==========================================================================
static void AddToVertex(const sector_t * sec, TArray<int> & list)
{
int secno = int(sec-sectors);
@ -322,6 +448,7 @@ static void AddToVertex(const sector_t * sec, TArray<int> & list)
// Attach sectors to vertices - used to generate vertex height lists
//
//==========================================================================
static void InitVertexData()
{
TArray<int> * vt_sectorlists;
@ -391,7 +518,7 @@ static void InitVertexData()
//==========================================================================
//
// Group segs to sidedefs
//
//
//==========================================================================
@ -421,6 +548,12 @@ static int STACK_ARGS segcmp(const void *a, const void *b)
return xs_RoundToInt(FRACUNIT*(A->sidefrac - B->sidefrac));
}
//==========================================================================
//
// Group segs to sidedefs
//
//==========================================================================
static void PrepareSegs()
{
int *segcount = new int[numsides];
@ -503,17 +636,18 @@ static void PrepareSegs()
// Initialize the level data for the GL renderer
//
//==========================================================================
extern int restart;
void gl_PreprocessLevel()
{
int i;
static bool datadone=false;
static int datadone=-1;
if (!datadone)
if (datadone != restart)
{
datadone=true;
datadone = restart;
gl_InitData();
}
@ -548,6 +682,7 @@ void gl_PreprocessLevel()
// Cleans up all the GL data for the last level
//
//==========================================================================
void gl_CleanLevelData()
{
// Dynamic lights must be destroyed before the sector information here is deleted.
@ -587,17 +722,42 @@ void gl_CleanLevelData()
delete [] sectors[0].subsectors;
sectors[0].subsectors = NULL;
}
if (gamenodes && gamenodes!=nodes)
for (int i=0;i<numsubsectors;i++)
{
delete [] gamenodes;
gamenodes = NULL;
numgamenodes = 0;
for(int j=0;j<2;j++)
{
if (subsectors[i].portalcoverage[j].subsectors != NULL)
{
delete [] subsectors[i].portalcoverage[j].subsectors;
subsectors[i].portalcoverage[j].subsectors = NULL;
}
}
}
if (gamesubsectors && gamesubsectors!=subsectors)
for(unsigned i=0;i<portals.Size(); i++)
{
delete [] gamesubsectors;
gamesubsectors = NULL;
numgamesubsectors = 0;
delete portals[i];
}
portals.Clear();
}
//==========================================================================
//
//
//
//==========================================================================
CCMD(listmapsections)
{
for(int i=0;i<100;i++)
{
for (int j=0;j<numsubsectors;j++)
{
if (subsectors[j].mapsection == i)
{
Printf("Mapsection %d, sector %d, line %d\n", i, subsectors[j].render_sector->sectornum, int(subsectors[j].firstline->linedef-lines));
break;
}
}
}
}

View file

@ -66,6 +66,7 @@ EXTERN_CVAR (Float, gl_lights_size);
int ScriptDepth;
void gl_InitGlow(FScanner &sc);
void gl_ParseBrightmap(FScanner &sc, int);
void gl_DestroyUserShaders();
void gl_ParseHardwareShader(FScanner &sc, int deflump);
void gl_ParseSkybox(FScanner &sc);
void gl_ParseDetailTexture(FScanner &sc);
@ -1315,6 +1316,8 @@ void gl_ParseDefs()
const char *defsLump = NULL;
atterm( gl_ReleaseLights );
gl_ReleaseLights();
gl_DestroyUserShaders();
switch (gameinfo.gametype)
{
case GAME_Heretic:

View file

@ -258,6 +258,14 @@ void gl_InitModels()
lastLump = 0;
for(unsigned i=0;i<Models.Size();i++)
{
delete Models[i];
}
Models.Clear();
SpriteModelFrames.Clear();
DeleteModelHash();
// First, create models for each voxel
for (unsigned i = 0; i < Voxels.Size(); i++)
{

View file

@ -150,11 +150,12 @@ void gl_GetRenderStyle(FRenderStyle style, bool drawopaque, bool allowcolorblend
int *tm, int *sb, int *db, int *be)
{
static int blendstyles[] = { GL_ZERO, GL_ONE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA };
static int renderops[] = { 0, GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT, -1, -1, -1, -1};
static int renderops[] = { 0, GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 };
int srcblend = blendstyles[style.SrcAlpha&3];
int dstblend = blendstyles[style.DestAlpha&3];
int blendequation = renderops[style.BlendOp&7];
int blendequation = renderops[style.BlendOp&15];
int texturemode = drawopaque? TM_OPAQUE : TM_MODULATE;
if (style.Flags & STYLEF_ColorIsFixed)

View file

@ -538,7 +538,7 @@ void FGLRenderer::Clear(int left, int top, int right, int bottom, int palcolor,
{
int rt;
int offY = 0;
PalEntry p = palcolor==-1? (PalEntry)color : GPalette.BaseColors[palcolor];
PalEntry p = palcolor==-1 || color != 0? (PalEntry)color : GPalette.BaseColors[palcolor];
int width = right-left;
int height= bottom-top;

View file

@ -20,11 +20,12 @@ extern int extralight;
enum SectorRenderFlags
{
// This is used to avoid creating too many drawinfos
SSRF_RENDERFLOOR=1,
SSRF_RENDERCEILING=2,
SSRF_RENDER3DPLANES=4,
SSRF_RENDERALL=7,
SSRF_PROCESSED=8,
SSRF_RENDERFLOOR = 1,
SSRF_RENDERCEILING = 2,
SSRF_RENDER3DPLANES = 4,
SSRF_RENDERALL = 7,
SSRF_PROCESSED = 8,
SSRF_SEEN = 16,
};
struct GL_IRECT
@ -105,7 +106,7 @@ public:
void DrawScene(bool toscreen = false);
void DrawBlend(sector_t * viewsector);
void DrawPSprite (player_t * player,pspdef_t *psp,fixed_t sx, fixed_t sy, int cm_index, bool hudModelStep);
void DrawPSprite (player_t * player,pspdef_t *psp,fixed_t sx, fixed_t sy, int cm_index, bool hudModelStep, int OverrideShader);
void DrawPlayerSprites(sector_t * viewsector, bool hudModelStep);
void DrawTargeterSprites();

View file

@ -62,6 +62,26 @@ CVAR(Bool, gl_render_things, true, 0)
CVAR(Bool, gl_render_walls, true, 0)
CVAR(Bool, gl_render_flats, true, 0)
static void UnclipSubsector(subsector_t *sub)
{
int count = sub->numlines;
seg_t * seg = sub->firstline;
while (count--)
{
angle_t startAngle = seg->v2->GetClipAngle();
angle_t endAngle = seg->v1->GetClipAngle();
// Back side, i.e. backface culling - read: endAngle >= startAngle!
if (startAngle-endAngle >= ANGLE_180)
{
clipper.SafeRemoveClipRange(startAngle, endAngle);
}
seg++;
}
}
//==========================================================================
//
// R_AddLine
@ -76,6 +96,13 @@ static sector_t *currentsector;
static void AddLine (seg_t *seg)
{
#ifdef _MSC_VER
#ifdef _DEBUG
if (seg->linedef-lines==38)
__asm nop
#endif
#endif
angle_t startAngle, endAngle;
sector_t * backsector = NULL;
sector_t bs;
@ -367,6 +394,17 @@ static void DoSubsector(subsector_t * sub)
sector=sub->sector;
if (!sector) return;
// If the mapsections differ this subsector can't possibly be visible from the current view point
if (!(currentmapsection[sub->mapsection>>3] & (1 << (sub->mapsection & 7)))) return;
if (gl_drawinfo->ss_renderflags[sub-subsectors] & SSRF_SEEN)
{
// This means that we have reached a subsector in a portal that has been marked 'seen'
// from the other side of the portal. This means we must clear the clipper for the
// range this subsector spans before going on.
UnclipSubsector(sub);
}
fakesector=gl_FakeFlat(sector, &fake, false);
if (sector->validcount != validcount)
@ -426,6 +464,14 @@ static void DoSubsector(subsector_t * sub)
// Due to the way a BSP works such a subsector can never be visible
if (!sector->heightsec || sector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC || in_area!=area_default)
{
if (sector != sub->render_sector)
{
sector = sub->render_sector;
// the planes of this subsector are faked to belong to another sector
// This means we need the heightsec parts and light info of the render sector, not the actual one.
fakesector = gl_FakeFlat(sector, &fake, false);
}
BYTE &srf = gl_drawinfo->sectorrenderflags[sub->render_sector->sectornum];
if (!(srf & SSRF_PROCESSED))
{
@ -434,13 +480,6 @@ static void DoSubsector(subsector_t * sub)
SetupFlat.Clock();
//if (!gl_multithreading)
{
if (sector != sub->render_sector)
{
sector = sub->render_sector;
// the planes of this subsector are faked to belong to another sector
// This means we need the heightsec parts and light info of the render sector, not the actual one!
fakesector = gl_FakeFlat(sector, &fake, false);
}
GLRenderer->ProcessSector(fakesector);
}
/*
@ -456,6 +495,22 @@ static void DoSubsector(subsector_t * sub)
gl_drawinfo->ss_renderflags[sub-subsectors] =
(sub->numlines > 2) ? SSRF_PROCESSED|SSRF_RENDERALL : SSRF_PROCESSED;
if (sub->hacked & 1) gl_drawinfo->AddHackedSubsector(sub);
FPortal *portal;
portal = fakesector->portals[sector_t::ceiling];
if (portal != NULL)
{
GLSectorStackPortal *glportal = portal->GetGLPortal();
glportal->AddSubsector(sub);
}
portal = fakesector->portals[sector_t::floor];
if (portal != NULL)
{
GLSectorStackPortal *glportal = portal->GetGLPortal();
glportal->AddSubsector(sub);
}
}
}
}
@ -496,7 +551,8 @@ void gl_RenderBSPNode (void *node)
// It is not necessary to use the slower precise version here
if (!clipper.CheckBox(bsp->bbox[side]))
{
return;
if (!(gl_drawinfo->no_renderflags[bsp-nodes] & SSRF_SEEN))
return;
}
node = bsp->children[side];

View file

@ -93,6 +93,14 @@ void Clipper::Clear()
ClipNode *node = cliphead;
ClipNode *temp;
while (node != NULL)
{
temp = node;
node = node->next;
temp->Free();
}
node = silhouette;
while (node != NULL)
{
temp = node;
@ -101,9 +109,32 @@ void Clipper::Clear()
}
cliphead = NULL;
silhouette = NULL;
anglecache++;
}
//-----------------------------------------------------------------------------
//
// SetSilhouette
//
//-----------------------------------------------------------------------------
void Clipper::SetSilhouette()
{
ClipNode *node = cliphead;
ClipNode *last = NULL;
while (node != NULL)
{
ClipNode *snode = ClipNode::NewRange(node->start, node->end);
if (silhouette == NULL) silhouette = snode;
snode->prev = last;
if (last != NULL) last->next = snode;
last = snode;
node = node->next;
}
}
//-----------------------------------------------------------------------------
//
@ -243,8 +274,42 @@ void Clipper::AddClipRange(angle_t start, angle_t end)
void Clipper::RemoveClipRange(angle_t start, angle_t end)
{
ClipNode *node, *temp;
ClipNode *node;
if (silhouette)
{
node = silhouette;
while (node != NULL && node->end <= start)
{
node = node->next;
}
if (node != NULL && node->start <= start)
{
if (node->end >= end) return;
start = node->end;
node = node->next;
}
while (node != NULL && node->start < end)
{
DoRemoveClipRange(start, node->start);
start = node->end;
node = node->next;
}
if (start >= end) return;
}
DoRemoveClipRange(start, end);
}
//-----------------------------------------------------------------------------
//
// RemoveClipRange worker function
//
//-----------------------------------------------------------------------------
void Clipper::DoRemoveClipRange(angle_t start, angle_t end)
{
ClipNode *node, *temp;
if (cliphead)
{
//check to see if range contains any old ranges

View file

@ -51,12 +51,14 @@ class Clipper
{
ClipNode * clipnodes;
ClipNode * cliphead;
ClipNode * silhouette; // will be preserved even when RemoveClipRange is called
static angle_t AngleToPseudo(angle_t ang);
bool IsRangeVisible(angle_t startangle, angle_t endangle);
void RemoveRange(ClipNode * cn);
void AddClipRange(angle_t startangle, angle_t endangle);
void RemoveClipRange(angle_t startangle, angle_t endangle);
void DoRemoveClipRange(angle_t start, angle_t end);
public:
@ -72,6 +74,7 @@ public:
void Clear();
void SetSilhouette();
bool SafeCheckRange(angle_t startAngle, angle_t endAngle)
{

View file

@ -44,6 +44,7 @@
#include "r_main.h"
#include "gl/system/gl_cvars.h"
#include "gl/data/gl_data.h"
#include "gl/scene/gl_drawinfo.h"
#include "gl/scene/gl_portal.h"
#include "gl/dynlights/gl_lightbuffer.h"
@ -939,9 +940,11 @@ void FDrawInfo::StartScene()
sectorrenderflags.Resize(numsectors);
ss_renderflags.Resize(numsubsectors);
no_renderflags.Resize(numsubsectors);
memset(&sectorrenderflags[0], 0, numsectors*sizeof(sectorrenderflags[0]));
memset(&ss_renderflags[0], 0, numsubsectors*sizeof(ss_renderflags[0]));
memset(&no_renderflags[0], 0, numnodes*sizeof(no_renderflags[0]));
next=gl_drawinfo;
gl_drawinfo=this;

View file

@ -191,6 +191,7 @@ struct FDrawInfo
TArray<BYTE> sectorrenderflags;
TArray<BYTE> ss_renderflags;
TArray<BYTE> no_renderflags;
TArray<MissingTextureInfo> MissingUpperTextures;
TArray<MissingTextureInfo> MissingLowerTextures;

View file

@ -44,6 +44,7 @@
#include "r_sky.h"
#include "gl/renderer/gl_renderer.h"
#include "gl/scene/gl_clipper.h"
#include "gl/data/gl_data.h"
//==========================================================================
@ -70,10 +71,11 @@ bool gl_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsecto
// Lines with stacked sectors must never block!
if (backsector->CeilingSkyBox && backsector->CeilingSkyBox->bAlways) return false;
if (backsector->FloorSkyBox && backsector->FloorSkyBox->bAlways) return false;
if (frontsector->CeilingSkyBox && frontsector->CeilingSkyBox->bAlways) return false;
if (frontsector->FloorSkyBox && frontsector->FloorSkyBox->bAlways) return false;
if (backsector->portals[sector_t::ceiling] != NULL || backsector->portals[sector_t::floor] != NULL ||
frontsector->portals[sector_t::ceiling] != NULL || frontsector->portals[sector_t::floor] != NULL)
{
return false;
}
// on large levels this distinction can save some time
// That's a lot of avoided multiplications if there's a lot to see!
@ -206,7 +208,23 @@ bool CopyPlaneIfValid (secplane_t *dest, const secplane_t *source, const secplan
//==========================================================================
sector_t * gl_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back)
{
if (!sec->heightsec || sec->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC || sec->heightsec==sec) return sec;
if (!sec->heightsec || sec->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC || sec->heightsec==sec)
{
// check for backsectors with the ceiling lower than the floor. These will create
// visual glitches because upper amd lower textures overlap.
if (back && sec->planes[sector_t::floor].TexZ > sec->planes[sector_t::ceiling].TexZ)
{
if (!(sec->floorplane.a | sec->floorplane.b | sec->ceilingplane.a | sec->ceilingplane.b))
{
*dest = *sec;
dest->ceilingplane=sec->floorplane;
dest->ceilingplane.FlipVert();
dest->planes[sector_t::ceiling].TexZ = dest->planes[sector_t::floor].TexZ;
return dest;
}
}
return sec;
}
#ifdef _MSC_VER
#ifdef _DEBUG
@ -224,8 +242,13 @@ sector_t * gl_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac
int diffTex = (sec->heightsec->MoreFlags & SECF_CLIPFAKEPLANES);
sector_t * s = sec->heightsec;
*dest=*sec;
#if 0
*dest=*sec; // This will invoke the copy operator which isn't really needed here. Memcpy is faster.
#else
memcpy(dest, sec, sizeof(sector_t));
#endif
// Replace floor and ceiling height with control sector's heights.
if (diffTex)
{
@ -298,6 +321,10 @@ sector_t * gl_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac
dest->vboindex[sector_t::ceiling] = sec->vboindex[sector_t::vbo_fakefloor];
dest->vboheight[sector_t::ceiling] = s->vboheight[sector_t::floor];
if (!(s->MoreFlags & SECF_NOFAKELIGHT))
{
dest->lightlevel = s->lightlevel;
}
if (!back)
{
@ -323,7 +350,6 @@ sector_t * gl_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac
if (!(s->MoreFlags & SECF_NOFAKELIGHT))
{
dest->lightlevel = s->lightlevel;
dest->SetPlaneLight(sector_t::floor, s->GetPlaneLight(sector_t::floor));
dest->SetPlaneLight(sector_t::ceiling, s->GetPlaneLight(sector_t::ceiling));
dest->ChangeFlags(sector_t::floor, -1, s->GetFlags(sector_t::floor));
@ -346,6 +372,11 @@ sector_t * gl_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac
dest->vboindex[sector_t::ceiling] = sec->vboindex[sector_t::ceiling];
dest->vboheight[sector_t::ceiling] = sec->vboheight[sector_t::ceiling];
if (!(s->MoreFlags & SECF_NOFAKELIGHT))
{
dest->lightlevel = s->lightlevel;
}
if (!back)
{
dest->SetTexture(sector_t::ceiling, diffTex ? sec->GetTexture(sector_t::ceiling) : s->GetTexture(sector_t::ceiling), false);

View file

@ -449,11 +449,6 @@ inline void GLFlat::PutFlat(bool fog)
{
Colormap.GetFixedColormap();
}
if ((gl.flags&RFL_NOSTENCIL) && !(renderflags&SSRF_RENDER3DPLANES))
{
renderstyle=STYLE_Translucent;
alpha=1.f;
}
if (renderstyle!=STYLE_Translucent || alpha < 1.f - FLT_EPSILON || fog)
{
int list = (renderflags&SSRF_RENDER3DPLANES) ? GLDL_TRANSLUCENT : GLDL_TRANSLUCENTBORDER;
@ -602,14 +597,20 @@ void GLFlat::ProcessSector(sector_t * frontsector)
if (frontsector->floorplane.ZatPoint(FIXED2FLOAT(viewx), FIXED2FLOAT(viewy)) <= FIXED2FLOAT(viewz))
{
// process the original floor first.
if (frontsector->FloorSkyBox && frontsector->FloorSkyBox->bAlways) gl_drawinfo->AddFloorStack(sector);
srf |= SSRF_RENDERFLOOR;
lightlevel = GetFloorLight(frontsector);
Colormap=frontsector->ColorMap;
stack = frontsector->FloorSkyBox && frontsector->FloorSkyBox->bAlways;
alpha= stack ? frontsector->FloorSkyBox->PlaneAlpha/65536.0f : 1.0f-frontsector->GetFloorReflect();
if ((stack = (frontsector->portals[sector_t::floor] != NULL)))
{
gl_drawinfo->AddFloorStack(sector);
alpha = frontsector->GetAlpha(sector_t::floor)/65536.0f;
}
else
{
alpha = 1.0f-frontsector->GetReflect(sector_t::floor);
}
if (frontsector->VBOHeightcheck(sector_t::floor))
{
vboindex = frontsector->vboindex[sector_t::floor];
@ -644,14 +645,21 @@ void GLFlat::ProcessSector(sector_t * frontsector)
if (frontsector->ceilingplane.ZatPoint(FIXED2FLOAT(viewx), FIXED2FLOAT(viewy)) >= FIXED2FLOAT(viewz))
{
// process the original ceiling first.
if (frontsector->CeilingSkyBox && frontsector->CeilingSkyBox->bAlways) gl_drawinfo->AddCeilingStack(sector);
srf |= SSRF_RENDERCEILING;
lightlevel = GetCeilingLight(frontsector);
Colormap=frontsector->ColorMap;
stack = frontsector->CeilingSkyBox && frontsector->CeilingSkyBox->bAlways;
alpha=stack ? frontsector->CeilingSkyBox->PlaneAlpha/65536.0f : 1.0f-frontsector->GetCeilingReflect();
if ((stack = (frontsector->portals[sector_t::ceiling] != NULL)))
{
gl_drawinfo->AddCeilingStack(sector);
alpha = frontsector->GetAlpha(sector_t::ceiling)/65536.0f;
}
else
{
alpha = 1.0f-frontsector->GetReflect(sector_t::ceiling);
}
if (frontsector->VBOHeightcheck(sector_t::ceiling))
{
vboindex = frontsector->vboindex[sector_t::ceiling];

View file

@ -83,13 +83,11 @@ int GLPortal::renderdepth;
int GLPortal::PlaneMirrorMode;
GLuint GLPortal::QueryObject;
bool GLPortal::inupperstack;
bool GLPortal::inlowerstack;
int GLPortal::instack[2];
bool GLPortal::inskybox;
UniqueList<GLSkyInfo> UniqueSkies;
UniqueList<GLHorizonInfo> UniqueHorizons;
UniqueList<GLSectorStackInfo> UniqueStacks;
UniqueList<secplane_t> UniquePlaneMirrors;
@ -104,7 +102,6 @@ void GLPortal::BeginScene()
{
UniqueSkies.Clear();
UniqueHorizons.Clear();
UniqueStacks.Clear();
UniquePlaneMirrors.Clear();
}
@ -292,6 +289,9 @@ bool GLPortal::Start(bool usestencil, bool doquery)
savedviewactor=GLRenderer->mViewActor;
savedviewangle=viewangle;
savedviewarea=in_area;
NextPortal = GLRenderer->mCurrentPortal;
GLRenderer->mCurrentPortal = NULL; // Portals which need this have to set it themselves
PortalAll.Unclock();
return true;
}
@ -325,6 +325,8 @@ inline void GLPortal::ClearClipper()
angle_t a1 = GLRenderer->FrustumAngle();
if (a1<ANGLE_180) clipper.SafeAddClipRangeRealAngles(viewangle+a1, viewangle-a1);
// lock the parts that have just been clipped out.
clipper.SetSilhouette();
}
//-----------------------------------------------------------------------------
@ -337,6 +339,7 @@ void GLPortal::End(bool usestencil)
bool needdepth = NeedDepthBuffer();
PortalAll.Clock();
GLRenderer->mCurrentPortal = NextPortal;
if (clipsave) gl.Enable (GL_CLIP_PLANE0+renderdepth-1);
if (usestencil)
{
@ -435,7 +438,8 @@ void GLPortal::StartFrame()
portals.Push(p);
if (renderdepth==0)
{
inskybox=inupperstack=inlowerstack=false;
inskybox=false;
instack[sector_t::floor]=instack[sector_t::ceiling]=0;
}
renderdepth++;
}
@ -466,6 +470,15 @@ void GLPortal::EndFrame()
{
GLPortal * p;
if (gl.flags & RFL_NOSTENCIL)
{
while (portals.Pop(p) && p)
{
delete p;
}
return;
}
if (gl_portalinfo)
{
Printf("%s%d portals, depth = %d\n%s{\n", indent.GetChars(), portals.Size(), renderdepth, indent.GetChars());
@ -483,8 +496,10 @@ void GLPortal::EndFrame()
{
Printf("%sProcessing %s, depth = %d, query = %d\n", indent.GetChars(), p->GetName(), renderdepth, usequery);
}
p->RenderPortal(true, usequery);
if (p->lines.Size() > 0)
{
p->RenderPortal(true, usequery);
}
delete p;
}
renderdepth--;
@ -517,7 +532,7 @@ bool GLPortal::RenderFirstSkyPortal(int recursion)
for(unsigned i=portals.Size()-1;i>=0 && portals[i]!=NULL;i--)
{
p=portals[i];
if (p->IsSky())
if (p->lines.Size() > 0 && p->IsSky())
{
// Cannot clear the depth buffer inside a portal recursion
if (recursion && p->NeedDepthBuffer()) continue;
@ -532,9 +547,8 @@ bool GLPortal::RenderFirstSkyPortal(int recursion)
if (best)
{
best->RenderPortal(false, false);
portals.Delete(bestindex);
best->RenderPortal(false, false);
delete best;
return true;
}
@ -547,6 +561,7 @@ bool GLPortal::RenderFirstSkyPortal(int recursion)
// FindPortal
//
//-----------------------------------------------------------------------------
GLPortal * GLPortal::FindPortal(const void * src)
{
int i=portals.Size()-1;
@ -556,6 +571,23 @@ GLPortal * GLPortal::FindPortal(const void * src)
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void GLPortal::SaveMapSection()
{
savedmapsection.Resize(currentmapsection.Size());
memcpy(&savedmapsection[0], &currentmapsection[0], currentmapsection.Size());
memset(&currentmapsection[0], 0, currentmapsection.Size());
}
void GLPortal::RestoreMapSection()
{
memcpy(&currentmapsection[0], &savedmapsection[0], currentmapsection.Size());
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
@ -611,6 +643,12 @@ void GLSkyboxPortal::DrawContents()
GLRenderer->SetupView(viewx, viewy, viewz, viewangle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1));
GLRenderer->SetViewArea();
ClearClipper();
int mapsection = R_PointInSubsector(viewx, viewy)->mapsection;
SaveMapSection();
currentmapsection[mapsection>>3] |= 1 << (mapsection & 7);
GLRenderer->DrawScene();
origin->flags&=~MF_JUSTHIT;
inskybox=false;
@ -619,6 +657,60 @@ void GLSkyboxPortal::DrawContents()
PlaneMirrorMode=old_pm;
extralight = saved_extralight;
RestoreMapSection();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
//
// Sector stack Portal
//
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
// GLSectorStackPortal::SetupCoverage
//
//-----------------------------------------------------------------------------
static BYTE SetCoverage(void *node)
{
if (numnodes == 0)
{
return 0;
}
if (!((size_t)node & 1)) // Keep going until found a subsector
{
node_t *bsp = (node_t *)node;
BYTE coverage = SetCoverage(bsp->children[0]) | SetCoverage(bsp->children[1]);
gl_drawinfo->no_renderflags[bsp-nodes] = coverage;
return coverage;
}
else
{
subsector_t *sub = (subsector_t *)((BYTE *)node - 1);
return gl_drawinfo->ss_renderflags[sub-subsectors] & SSRF_SEEN;
}
}
void GLSectorStackPortal::SetupCoverage()
{
for(unsigned i=0; i<subsectors.Size(); i++)
{
subsector_t *sub = subsectors[i];
int plane = origin->plane;
for(int j=0;j<sub->portalcoverage[plane].sscount; j++)
{
subsector_t *dsub = &::subsectors[sub->portalcoverage[plane].subsectors[j]];
currentmapsection[dsub->mapsection>>3] |= 1 << (dsub->mapsection&7);
gl_drawinfo->ss_renderflags[dsub-::subsectors] |= SSRF_SEEN;
}
}
SetCoverage(&nodes[numnodes-1]);
}
//-----------------------------------------------------------------------------
@ -628,11 +720,10 @@ void GLSkyboxPortal::DrawContents()
//-----------------------------------------------------------------------------
void GLSectorStackPortal::DrawContents()
{
FPortal *portal = &::portals[origin->origin->special1];
portal->UpdateClipAngles();
FPortal *portal = origin;
viewx += origin->origin->x - origin->origin->Mate->x;
viewy += origin->origin->y - origin->origin->Mate->y;
viewx += origin->xDisplacement;
viewy += origin->yDisplacement;
GLRenderer->mViewActor = NULL;
GLRenderer->mCurrentPortal = this;
@ -640,153 +731,34 @@ void GLSectorStackPortal::DrawContents()
validcount++;
// avoid recursions!
if (origin->isupper) inupperstack=true;
else inlowerstack=true;
if (origin->plane != -1) instack[origin->plane]++;
GLRenderer->SetupView(viewx, viewy, viewz, viewangle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1));
SaveMapSection();
SetupCoverage();
ClearClipper();
GLRenderer->DrawScene();
RestoreMapSection();
if (origin->plane != -1) instack[origin->plane]--;
}
//-----------------------------------------------------------------------------
//
// GLSectorStackPortal::ClipSeg
//
//-----------------------------------------------------------------------------
int GLSectorStackPortal::ClipSeg(seg_t *seg)
{
FPortal *portal = &::portals[origin->origin->special1];
angle_t *angles = &portal->ClipAngles[0];
unsigned numpoints = portal->ClipAngles.Size()-1;
angle_t clipangle = seg->v1->GetClipAngle();
unsigned i, j;
int relation;
// Check the front side of the portal. Anything in front of the shape must be discarded by the clipper.
for(i=0;i<numpoints; i++)
{
if (angles[i+1] - clipangle <= ANGLE_180 && angles[i] - clipangle > ANGLE_180 && angles[i+1] - angles[i] < ANGLE_180)
{
relation = DMulScale32(seg->v1->y - portal->Shape[i]->y - portal->yDisplacement, portal->Shape[i+1]->x - portal->Shape[i]->x,
portal->Shape[i]->x - seg->v1->x + portal->xDisplacement, portal->Shape[i+1]->y - portal->Shape[i]->y);
if (relation > 0)
{
return PClip_InFront;
}
else if (relation == 0)
{
// If this vertex is on the boundary we need to check the second one, too. The line may be partially inside the shape
// but outside the portal. We can use the same boundary line for this
relation = DMulScale32(seg->v2->y - portal->Shape[i]->y - portal->yDisplacement, portal->Shape[i+1]->x - portal->Shape[i]->x,
portal->Shape[i]->x - seg->v2->x + portal->xDisplacement, portal->Shape[i+1]->y - portal->Shape[i]->y);
if (relation >= 0) return PClip_InFront;
}
return PClip_Inside;
}
}
// The first vertex did not yield any useful result. Check the second one.
clipangle = seg->v2->GetClipAngle();
for(j=0;j<numpoints; j++)
{
if (angles[j+1] - clipangle <= ANGLE_180 && angles[j] - clipangle > ANGLE_180 && angles[j+1] - angles[j] < ANGLE_180)
{
relation = DMulScale32(seg->v2->y - portal->Shape[j]->y - portal->yDisplacement, portal->Shape[j+1]->x - portal->Shape[j]->x,
portal->Shape[j]->x - seg->v1->x + portal->xDisplacement, portal->Shape[j+1]->y - portal->Shape[j]->y);
if (relation > 0)
{
return PClip_InFront;
}
else if (relation == 0)
{
// If this vertex is on the boundary we need to check the second one, too. The line may be partially inside the shape
// but outside the portal. We can use the same boundary line for this
relation = DMulScale32(seg->v2->y - portal->Shape[j]->y - portal->yDisplacement, portal->Shape[j+1]->x - portal->Shape[j]->x,
portal->Shape[j]->x - seg->v2->x + portal->xDisplacement, portal->Shape[j+1]->y - portal->Shape[j]->y);
if (relation >= 0) return PClip_InFront;
}
return PClip_Inside;
}
}
return PClip_Inside; // The viewpoint is inside the portal
#if 0
// Check backside of portal
for(i=0;i<numpoints; i++)
{
if (angles[i+1] - clipangle > ANGLE_180 && angles[i] - clipangle <= ANGLE_180)
{
relation1 = DMulScale32(seg->v1->y - portal->Shape[i]->y - portal->yDisplacement, portal->Shape[i+1]->x - portal->Shape[i]->x,
portal->Shape[i]->x - seg->v1->x + portal->xDisplacement, portal->Shape[i+1]->y - portal->Shape[i]->y);
if (relation1 < 0) return PClip_Inside;
// If this vertex is inside we need to check the second one, too. The line may be partially inside the shape
// but outside the portal.
break;
}
}
clipangle = seg->v2->GetClipAngle();
for(j=0;j<numpoints; j++)
{
if (angles[j+1] - clipangle > ANGLE_180 && angles[j] - clipangle <= ANGLE_180)
{
relation2 = DMulScale32(seg->v2->y - portal->Shape[j]->y - portal->yDisplacement, portal->Shape[j+1]->x - portal->Shape[j]->x,
portal->Shape[j]->x - seg->v2->x + portal->xDisplacement, portal->Shape[j+1]->y - portal->Shape[j]->y);
if (relation2 < 0) return PClip_Inside;
break;
}
}
return PClip_Behind;
#endif
}
//-----------------------------------------------------------------------------
//
// GLSectorStackPortal::ClipPoint
//
// Plane Mirror Portal
//
//
//-----------------------------------------------------------------------------
int GLSectorStackPortal::ClipPoint(fixed_t x, fixed_t y)
{
FPortal *portal = &::portals[origin->origin->special1];
angle_t *angles = &portal->ClipAngles[0];
unsigned numpoints = portal->ClipAngles.Size()-1;
angle_t clipangle = R_PointToPseudoAngle(viewx, viewy, x, y);
unsigned i;
for(i=0;i<numpoints; i++)
{
if (angles[i+1] - clipangle <= ANGLE_180 && angles[i] - clipangle > ANGLE_180 && angles[i+1] - angles[i] < ANGLE_180)
{
int relation = DMulScale32(y - portal->Shape[i]->y - portal->yDisplacement, portal->Shape[i+1]->x - portal->Shape[i]->x,
portal->Shape[i]->x - x + portal->xDisplacement, portal->Shape[i+1]->y - portal->Shape[i]->y);
if (relation > 0) return PClip_InFront;
return PClip_Inside;
}
}
return PClip_Inside;
/*
for(i=0;i<numpoints; i++)
{
if (clipangle >= angles[i] && clipangle < angles[i+1])
{
int relation = DMulScale32(y - portal->Shape[i]->y, portal->Shape[i+1]->x - portal->Shape[i]->x,
portal->Shape[i]->x - x, portal->Shape[i+1]->y - portal->Shape[i]->y);
if (relation > 0) return PClip_InFront;
return PClip_Inside;
}
}
*/
return PClip_Inside;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//
// GLPlaneMirrorPortal::DrawContents
//
//-----------------------------------------------------------------------------
void GLPlaneMirrorPortal::DrawContents()
{
if (renderdepth>r_mirror_recursions)
@ -820,6 +792,13 @@ void GLPlaneMirrorPortal::DrawContents()
PlaneMirrorMode=old_pm;
}
//-----------------------------------------------------------------------------
//
// GLPlaneMirrorPortal::DrawContents
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

View file

@ -72,17 +72,8 @@ struct GLSkyInfo
}
};
struct GLSectorStackInfo
{
ASkyViewpoint *origin;
bool isupper;
};
extern UniqueList<GLSkyInfo> UniqueSkies;
extern UniqueList<GLHorizonInfo> UniqueHorizons;
extern UniqueList<GLSectorStackInfo> UniqueStacks;
extern UniqueList<secplane_t> UniquePlaneMirrors;
class GLPortal
@ -97,8 +88,8 @@ protected:
public:
static int PlaneMirrorMode;
static bool inupperstack;
static bool inlowerstack;
static int inupperstack;
static int instack[2];
static bool inskybox;
private:
@ -111,6 +102,8 @@ private:
AActor * savedviewactor;
area_t savedviewarea;
unsigned char clipsave;
GLPortal *NextPortal;
TArray<BYTE> savedmapsection;
protected:
TArray<GLWall> lines;
@ -129,6 +122,8 @@ protected:
virtual bool NeedDepthBuffer() { return true; }
void ClearScreen();
virtual const char *GetName() = 0;
void SaveMapSection();
void RestoreMapSection();
public:
@ -241,21 +236,25 @@ public:
struct GLSectorStackPortal : public GLPortal
{
TArray<subsector_t *> subsectors;
protected:
virtual void DrawContents();
virtual void * GetSource() const { return origin; }
virtual bool IsSky() { return true; } // although this isn't a real sky it can be handled as one.
virtual const char *GetName();
GLSectorStackInfo * origin;
FPortal *origin;
public:
GLSectorStackPortal(GLSectorStackInfo * pt)
GLSectorStackPortal(FPortal *pt)
{
origin=pt;
}
int ClipSeg(seg_t *seg);
int ClipPoint(fixed_t x, fixed_t y);
void SetupCoverage();
void AddSubsector(subsector_t *sub)
{
subsectors.Push(sub);
}
};

View file

@ -49,6 +49,7 @@
#include "gl/dynlights/gl_glow.h"
#include "gl/dynlights/gl_lightbuffer.h"
#include "gl/scene/gl_drawinfo.h"
#include "gl/scene/gl_portal.h"
#include "gl/utility/gl_clock.h"
#include "gl/utility/gl_templates.h"
@ -679,7 +680,7 @@ void FDrawInfo::DrawUnhandledMissingTextures()
if (seg->PartnerSeg && (seg->PartnerSeg->Subsector()->flags & SSECF_DEGENERATE)) continue;
if (seg->backsector->transdoor) continue;
if (seg->backsector->GetTexture(sector_t::ceiling)==skyflatnum) continue;
if (seg->backsector->CeilingSkyBox && seg->backsector->CeilingSkyBox->bAlways) continue;
if (seg->backsector->portals[sector_t::ceiling] != NULL) continue;
if (!glset.notexturefill) FloodUpperGap(seg);
}
@ -699,7 +700,7 @@ void FDrawInfo::DrawUnhandledMissingTextures()
if (seg->frontsector->GetPlaneTexZ(sector_t::floor) > viewz) continue; // out of sight
if (seg->backsector->transdoor) continue;
if (seg->backsector->GetTexture(sector_t::floor)==skyflatnum) continue;
if (seg->backsector->FloorSkyBox && seg->backsector->FloorSkyBox->bAlways) continue;
if (seg->backsector->portals[sector_t::floor] != NULL) continue;
if (!glset.notexturefill) FloodLowerGap(seg);
}
@ -1058,7 +1059,7 @@ void FDrawInfo::CollectSectorStacksCeiling(subsector_t * sub, sector_t * anchor)
sub->validcount=validcount;
// Has a sector stack or skybox itself!
if (sub->render_sector->CeilingSkyBox && sub->render_sector->CeilingSkyBox->bAlways) return;
if (sub->render_sector->portals[sector_t::ceiling] != NULL) return;
// Don't bother processing unrendered subsectors
if (sub->numlines>2 && !(ss_renderflags[DWORD(sub-subsectors)]&SSRF_PROCESSED)) return;
@ -1106,7 +1107,7 @@ void FDrawInfo::CollectSectorStacksFloor(subsector_t * sub, sector_t * anchor)
sub->validcount=validcount;
// Has a sector stack or skybox itself!
if (sub->render_sector->FloorSkyBox && sub->render_sector->FloorSkyBox->bAlways) return;
if (sub->render_sector->portals[sector_t::floor] != NULL) return;
// Don't bother processing unrendered subsectors
if (sub->numlines>2 && !(ss_renderflags[DWORD(sub-subsectors)]&SSRF_PROCESSED)) return;
@ -1155,7 +1156,8 @@ void FDrawInfo::ProcessSectorStacks()
for (i=0;i<CeilingStacks.Size (); i++)
{
sector_t *sec = CeilingStacks[i];
for(int k=0;k<sec->subsectorcount;k++)
FPortal *portal = sec->portals[sector_t::ceiling];
if (portal != NULL) for(int k=0;k<sec->subsectorcount;k++)
{
subsector_t * sub = sec->subsectors[k];
if (ss_renderflags[sub-subsectors] & SSRF_PROCESSED)
@ -1173,12 +1175,20 @@ void FDrawInfo::ProcessSectorStacks()
}
for(unsigned int j=0;j<HandledSubsectors.Size();j++)
{
ss_renderflags[DWORD(HandledSubsectors[j]-subsectors)] &= ~SSRF_RENDERCEILING;
subsector_t *sub = HandledSubsectors[j];
ss_renderflags[DWORD(sub-subsectors)] &= ~SSRF_RENDERCEILING;
if (sub->render_sector->CeilingSkyBox->PlaneAlpha!=0)
if (sub->portalcoverage[sector_t::ceiling].subsectors == NULL)
{
gl_BuildPortalCoverage(&sub->portalcoverage[sector_t::ceiling], sub, portal);
}
portal->GetGLPortal()->AddSubsector(sub);
if (sec->GetAlpha(sector_t::ceiling) != 0)
{
gl_subsectorrendernode * node = SSR_List.GetNew();
node->sub = HandledSubsectors[j];
node->sub = sub;
AddOtherCeilingPlane(sub->render_sector->sectornum, node);
}
}
@ -1190,7 +1200,8 @@ void FDrawInfo::ProcessSectorStacks()
for (i=0;i<FloorStacks.Size (); i++)
{
sector_t *sec = FloorStacks[i];
for(int k=0;k<sec->subsectorcount;k++)
FPortal *portal = sec->portals[sector_t::floor];
if (portal != NULL) for(int k=0;k<sec->subsectorcount;k++)
{
subsector_t * sub = sec->subsectors[k];
if (ss_renderflags[sub-subsectors] & SSRF_PROCESSED)
@ -1209,13 +1220,21 @@ void FDrawInfo::ProcessSectorStacks()
for(unsigned int j=0;j<HandledSubsectors.Size();j++)
{
//Printf("%d: ss %d, sec %d\n", j, HandledSubsectors[j]-subsectors, HandledSubsectors[j]->render_sector->sectornum);
ss_renderflags[DWORD(HandledSubsectors[j]-subsectors)] &= ~SSRF_RENDERFLOOR;
subsector_t *sub = HandledSubsectors[j];
ss_renderflags[DWORD(sub-subsectors)] &= ~SSRF_RENDERFLOOR;
if (sub->render_sector->FloorSkyBox->PlaneAlpha!=0)
if (sub->portalcoverage[sector_t::floor].subsectors == NULL)
{
gl_BuildPortalCoverage(&sub->portalcoverage[sector_t::floor], sub, portal);
}
GLSectorStackPortal *glportal = portal->GetGLPortal();
glportal->AddSubsector(sub);
if (sec->GetAlpha(sector_t::floor)!=0)
{
gl_subsectorrendernode * node = SSR_List.GetNew();
node->sub = HandledSubsectors[j];
node->sub = sub;
AddOtherFloorPlane(sub->render_sector->sectornum, node);
}
}

View file

@ -91,6 +91,7 @@ extern int viewpitch;
DWORD gl_fixedcolormap;
area_t in_area;
TArray<BYTE> currentmapsection;
void R_SetupFrame (AActor * camera);
@ -312,6 +313,7 @@ void FGLRenderer::CreateScene()
ProcessAll.Clock();
// clip the scene and fill the drawlists
for(unsigned i=0;i<portals.Size(); i++) portals[i]->glportal = NULL;
gl_spriteindex=0;
Bsp.Clock();
gl_RenderBSPNode (nodes + numnodes - 1);
@ -847,6 +849,9 @@ void FGLRenderer::ProcessScene(bool toscreen)
iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0;
GLPortal::BeginScene();
int mapsection = R_PointInSubsector(viewx, viewy)->mapsection;
memset(&currentmapsection[0], 0, currentmapsection.Size());
currentmapsection[mapsection>>3] |= 1 << (mapsection & 7);
DrawScene(toscreen);
FDrawInfo::EndDrawInfo();
@ -951,9 +956,6 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo
//-----------------------------------------------------------------------------
static FRandom pr_glhom;
EXTERN_CVAR(Int, r_clearbuffer)
CVAR(Bool, gl_testdl, false, 0)
static int dl = -1;
static int indl = 0;
void FGLRenderer::RenderView (player_t* player)
{
@ -1035,31 +1037,9 @@ void FGLRenderer::RenderView (player_t* player)
TThinkerIterator<ADynamicLight> it(STAT_DLIGHT);
GLRenderer->mLightCount = ((it.Next()) != NULL);
if (gl_testdl)
{
if (dl == -1)
{
dl = glGenLists(1);
glNewList(dl, GL_COMPILE_AND_EXECUTE);
indl = true;
}
else
{
glCallList(dl);
All.Unclock();
return;
}
}
sector_t * viewsector = RenderViewpoint(player->camera, NULL, FieldOfView * 360.0f / FINEANGLES, ratio, fovratio, true, true);
EndDrawScene(viewsector);
if (gl_testdl && indl)
{
indl = false;
glEndList();
}
All.Unclock();
}

View file

@ -62,118 +62,104 @@ enum
};
//==========================================================================
//
// Calculate mirrorplane
//
//==========================================================================
void GLWall::MirrorPlane(secplane_t * plane, bool ceiling)
{
if (!(gl.flags&RFL_NOSTENCIL))
{
if (ceiling && FIXED2FLOAT(viewz) >= plane->ZatPoint(FIXED2FLOAT(viewx), FIXED2FLOAT(viewy))) return;
if (!ceiling && FIXED2FLOAT(viewz) <= plane->ZatPoint(FIXED2FLOAT(viewx), FIXED2FLOAT(viewy))) return;
type=RENDERWALL_PLANEMIRROR;
planemirror=plane;
PutWall(0);
}
}
//==========================================================================
//
// Calculate sky texture
//
//==========================================================================
void GLWall::SkyTexture(int sky1,ASkyViewpoint * skyboxx, bool ceiling)
void GLWall::SkyPlane(sector_t *sector, int plane, bool allowreflect)
{
GLSkyInfo skyinfo;
// JUSTHIT is used as an indicator that a skybox is in use.
// This is to avoid recursion
if (!gl_noskyboxes && !(gl.flags&RFL_NOSTENCIL) && skyboxx && GLRenderer->mViewActor!=skyboxx && !(skyboxx->flags&MF_JUSTHIT))
FPortal *portal = sector->portals[plane];
if (portal != NULL)
{
if (!skyboxx->Mate)
if (GLPortal::instack[1-plane]) return;
type=RENDERWALL_SECTORSTACK;
this->portal = portal;
}
else if (sector->GetTexture(plane)==skyflatnum)
{
GLSkyInfo skyinfo;
ASkyViewpoint * skyboxx = plane == sector_t::floor? sector->FloorSkyBox : sector->CeilingSkyBox;
// JUSTHIT is used as an indicator that a skybox is in use.
// This is to avoid recursion
if (!gl_noskyboxes && skyboxx && GLRenderer->mViewActor!=skyboxx && !(skyboxx->flags&MF_JUSTHIT))
{
type=RENDERWALL_SKYBOX;
skybox=skyboxx;
}
else
{
static GLSectorStackInfo stackinfo;
if (ceiling && GLPortal::inlowerstack) return;
if (!ceiling && GLPortal::inupperstack) return;
type=RENDERWALL_SECTORSTACK;
stackinfo.origin = skyboxx;
stackinfo.isupper= ceiling;
stack=&stackinfo;
}
}
else
{
if (skyboxx && skyboxx->Mate) return;
memset(&skyinfo, 0, sizeof(skyinfo));
if ((sky1 & PL_SKYFLAT) && (sky1 & (PL_SKYFLAT-1)) && !(gl.flags&RFL_NOSTENCIL))
{
const line_t *l = &lines[(sky1&(PL_SKYFLAT-1))-1];
const side_t *s = l->sidedef[0];
int pos;
if (level.flags & LEVEL_SWAPSKIES && s->GetTexture(side_t::bottom).isValid())
{
pos = side_t::bottom;
}
else
{
pos = side_t::top;
}
FTextureID texno = s->GetTexture(pos);
skyinfo.texture[0] = FMaterial::ValidateTexture(texno, true);
if (!skyinfo.texture[0] || skyinfo.texture[0]->tex->UseType == FTexture::TEX_Null) goto normalsky;
skyinfo.skytexno1 = texno;
skyinfo.x_offset[0] = ANGLE_TO_FLOAT(s->GetTextureXOffset(pos));
skyinfo.y_offset = FIXED2FLOAT(s->GetTextureYOffset(pos));
skyinfo.mirrored = !l->args[2];
}
else
{
normalsky:
if (level.flags&LEVEL_DOUBLESKY)
int sky1 = sector->sky;
memset(&skyinfo, 0, sizeof(skyinfo));
if ((sky1 & PL_SKYFLAT) && (sky1 & (PL_SKYFLAT-1)))
{
skyinfo.texture[1]=FMaterial::ValidateTexture(sky1texture, true);
if (!skyinfo.texture[1]) return;
skyinfo.x_offset[1] = GLRenderer->mSky1Pos;
skyinfo.doublesky = true;
}
if ((level.flags&LEVEL_SWAPSKIES || (sky1==PL_SKYFLAT && !(gl.flags&RFL_NOSTENCIL)) || (level.flags&LEVEL_DOUBLESKY)) &&
sky2texture!=sky1texture) // If both skies are equal use the scroll offset of the first!
{
skyinfo.texture[0]=FMaterial::ValidateTexture(sky2texture, true);
skyinfo.skytexno1=sky2texture;
skyinfo.sky2 = true;
skyinfo.x_offset[0] = GLRenderer->mSky2Pos;
const line_t *l = &lines[(sky1&(PL_SKYFLAT-1))-1];
const side_t *s = l->sidedef[0];
int pos;
if (level.flags & LEVEL_SWAPSKIES && s->GetTexture(side_t::bottom).isValid())
{
pos = side_t::bottom;
}
else
{
pos = side_t::top;
}
FTextureID texno = s->GetTexture(pos);
skyinfo.texture[0] = FMaterial::ValidateTexture(texno, true);
if (!skyinfo.texture[0] || skyinfo.texture[0]->tex->UseType == FTexture::TEX_Null) goto normalsky;
skyinfo.skytexno1 = texno;
skyinfo.x_offset[0] = ANGLE_TO_FLOAT(s->GetTextureXOffset(pos));
skyinfo.y_offset = FIXED2FLOAT(s->GetTextureYOffset(pos));
skyinfo.mirrored = !l->args[2];
}
else
{
skyinfo.texture[0]=FMaterial::ValidateTexture(sky1texture, true);
skyinfo.skytexno1=sky1texture;
skyinfo.x_offset[0] = GLRenderer->mSky1Pos;
normalsky:
if (level.flags&LEVEL_DOUBLESKY)
{
skyinfo.texture[1]=FMaterial::ValidateTexture(sky1texture, true);
skyinfo.x_offset[1] = GLRenderer->mSky1Pos;
skyinfo.doublesky = true;
}
if ((level.flags&LEVEL_SWAPSKIES || (sky1==PL_SKYFLAT) || (level.flags&LEVEL_DOUBLESKY)) &&
sky2texture!=sky1texture) // If both skies are equal use the scroll offset of the first!
{
skyinfo.texture[0]=FMaterial::ValidateTexture(sky2texture, true);
skyinfo.skytexno1=sky2texture;
skyinfo.sky2 = true;
skyinfo.x_offset[0] = GLRenderer->mSky2Pos;
}
else
{
skyinfo.texture[0]=FMaterial::ValidateTexture(sky1texture, true);
skyinfo.skytexno1=sky1texture;
skyinfo.x_offset[0] = GLRenderer->mSky1Pos;
}
}
if (!skyinfo.texture[0]) return;
if (skyfog>0)
{
skyinfo.fadecolor=Colormap.FadeColor;
skyinfo.fadecolor.a=0;
}
else skyinfo.fadecolor=0;
type=RENDERWALL_SKY;
sky=UniqueSkies.Get(&skyinfo);
}
if (skyfog>0)
{
skyinfo.fadecolor=Colormap.FadeColor;
skyinfo.fadecolor.a=0;
}
else skyinfo.fadecolor=0;
type=RENDERWALL_SKY;
sky = &skyinfo;
}
else if (allowreflect && sector->GetReflect(plane) > 0)
{
if ((plane == sector_t::ceiling && viewz > sector->ceilingplane.d) ||
(plane == sector_t::floor && viewz < -sector->floorplane.d)) return;
type=RENDERWALL_PLANEMIRROR;
planemirror = plane == sector_t::ceiling? &sector->ceilingplane : &sector->floorplane;
}
else return;
PutWall(0);
}
@ -183,34 +169,26 @@ void GLWall::SkyTexture(int sky1,ASkyViewpoint * skyboxx, bool ceiling)
// Skies on one sided walls
//
//==========================================================================
void GLWall::SkyNormal(sector_t * fs,vertex_t * v1,vertex_t * v2)
{
bool ceilingsky = fs->GetTexture(sector_t::ceiling)==skyflatnum || (fs->CeilingSkyBox && fs->CeilingSkyBox->bAlways);
if (ceilingsky || fs->ceiling_reflect)
{
ztop[0]=ztop[1]=32768.0f;
zbottom[0]=zceil[0];
zbottom[1]=zceil[1];
if (ceilingsky) SkyTexture(fs->sky,fs->CeilingSkyBox, true);
else MirrorPlane(&fs->ceilingplane, true);
}
bool floorsky = fs->GetTexture(sector_t::floor)==skyflatnum || (fs->FloorSkyBox && fs->FloorSkyBox->bAlways);
if (floorsky || fs->floor_reflect)
{
ztop[0]=zfloor[0];
ztop[1]=zfloor[1];
zbottom[0]=zbottom[1]=-32768.0f;
if (floorsky) SkyTexture(fs->sky,fs->FloorSkyBox, false);
else MirrorPlane(&fs->floorplane, false);
}
}
ztop[0]=ztop[1]=32768.0f;
zbottom[0]=zceil[0];
zbottom[1]=zceil[1];
SkyPlane(fs, sector_t::ceiling, true);
ztop[0]=zfloor[0];
ztop[1]=zfloor[1];
zbottom[0]=zbottom[1]=-32768.0f;
SkyPlane(fs, sector_t::floor, true);
}
//==========================================================================
//
// Upper Skies on two sided walls
//
//==========================================================================
void GLWall::SkyTop(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2)
{
if (fs->GetTexture(sector_t::ceiling)==skyflatnum)
@ -241,7 +219,7 @@ void GLWall::SkyTop(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex
ztop[0]=ztop[1]=32768.0f;
zbottom[0]=zbottom[1]=
FIXED2FLOAT(bs->ceilingplane.ZatPoint(v2) + seg->sidedef->GetTextureYOffset(side_t::mid));
SkyTexture(fs->sky,fs->CeilingSkyBox, true);
SkyPlane(fs, sector_t::ceiling, false);
return;
}
}
@ -263,25 +241,36 @@ void GLWall::SkyTop(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex
zbottom[1]=FIXED2FLOAT(bs->ceilingplane.ZatPoint(v2));
flags|=GLWF_SKYHACK; // mid textures on such lines need special treatment!
}
SkyTexture(fs->sky,fs->CeilingSkyBox, true);
}
else
{
bool ceilingsky = (fs->CeilingSkyBox && fs->CeilingSkyBox->bAlways && fs->CeilingSkyBox!=bs->CeilingSkyBox);
if (ceilingsky || fs->ceiling_reflect)
FPortal *pfront = fs->portals[sector_t::ceiling];
FPortal *pback = bs->portals[sector_t::ceiling];
float frontreflect = fs->GetReflect(sector_t::ceiling);
if (frontreflect > 0)
{
// stacked sectors
fixed_t fsc1=fs->ceilingplane.ZatPoint(v1);
fixed_t fsc2=fs->ceilingplane.ZatPoint(v2);
ztop[0]=ztop[1]=32768.0f;
zbottom[0]=FIXED2FLOAT(fsc1);
zbottom[1]=FIXED2FLOAT(fsc2);
if (ceilingsky) SkyTexture(fs->sky,fs->CeilingSkyBox, true);
else MirrorPlane(&fs->ceilingplane, true);
float backreflect = bs->GetReflect(sector_t::ceiling);
if (backreflect > 0 && bs->ceilingplane.d == fs->ceilingplane.d)
{
// Don't add intra-portal line to the portal.
return;
}
}
else if (pfront == NULL || pfront == pback)
{
return;
}
// stacked sectors
fixed_t fsc1=fs->ceilingplane.ZatPoint(v1);
fixed_t fsc2=fs->ceilingplane.ZatPoint(v2);
ztop[0]=ztop[1]=32768.0f;
zbottom[0]=FIXED2FLOAT(fsc1);
zbottom[1]=FIXED2FLOAT(fsc2);
}
SkyPlane(fs, sector_t::ceiling, true);
}
@ -290,6 +279,7 @@ void GLWall::SkyTop(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex
// Lower Skies on two sided walls
//
//==========================================================================
void GLWall::SkyBottom(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2)
{
if (fs->GetTexture(sector_t::floor)==skyflatnum)
@ -327,24 +317,35 @@ void GLWall::SkyBottom(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,ver
ztop[1]=FIXED2FLOAT(bs->floorplane.ZatPoint(v2));
flags|=GLWF_SKYHACK; // mid textures on such lines need special treatment!
}
SkyTexture(fs->sky,fs->FloorSkyBox, false);
}
else
{
bool floorsky = (fs->FloorSkyBox && fs->FloorSkyBox->bAlways && fs->FloorSkyBox!=bs->FloorSkyBox);
if (floorsky || fs->floor_reflect)
FPortal *pfront = fs->portals[sector_t::floor];
FPortal *pback = bs->portals[sector_t::floor];
float frontreflect = fs->GetReflect(sector_t::floor);
if (frontreflect > 0)
{
// stacked sectors
fixed_t fsc1=fs->floorplane.ZatPoint(v1);
fixed_t fsc2=fs->floorplane.ZatPoint(v2);
zbottom[0]=zbottom[1]=-32768.0f;
ztop[0]=FIXED2FLOAT(fsc1);
ztop[1]=FIXED2FLOAT(fsc2);
if (floorsky) SkyTexture(fs->sky,fs->FloorSkyBox, false);
else MirrorPlane(&fs->floorplane, false);
float backreflect = bs->GetReflect(sector_t::floor);
if (backreflect > 0 && bs->floorplane.d == fs->floorplane.d)
{
// Don't add intra-portal line to the portal.
return;
}
}
else if (pfront == NULL || pfront == pback)
{
return;
}
// stacked sectors
fixed_t fsc1=fs->floorplane.ZatPoint(v1);
fixed_t fsc2=fs->floorplane.ZatPoint(v2);
zbottom[0]=zbottom[1]=-32768.0f;
ztop[0]=FIXED2FLOAT(fsc1);
ztop[1]=FIXED2FLOAT(fsc2);
}
SkyPlane(fs, sector_t::floor, true);
}

View file

@ -67,6 +67,10 @@ CVAR(Float, gl_sclipfactor, 1.8, CVAR_ARCHIVE)
CVAR(Int, gl_particles_style, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // 0 = square, 1 = round, 2 = smooth
CVAR(Int, gl_billboard_mode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Int, gl_enhanced_nv_stealth, 3, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, gl_fuzztype, 0, CVAR_ARCHIVE)
{
if (self < 0 || self > 7) self = 0;
}
extern bool r_showviewer;
EXTERN_CVAR (Float, transsouls)
@ -136,7 +140,7 @@ void GLSprite::Draw(int pass)
gl_RenderState.AlphaFunc(GL_GEQUAL,trans*gl_mask_sprite_threshold);
}
if (RenderStyle.BlendOp == STYLEOP_Fuzz)
if (RenderStyle.BlendOp == STYLEOP_Shadow)
{
float fuzzalpha=0.44f;
float minalpha=0.1f;
@ -166,7 +170,7 @@ void GLSprite::Draw(int pass)
additivefog = true;
}
}
if (RenderStyle.BlendOp!=STYLEOP_Fuzz)
if (RenderStyle.BlendOp!=STYLEOP_Shadow)
{
if (actor)
{
@ -203,7 +207,7 @@ void GLSprite::Draw(int pass)
gl_SetFog(foglevel, rel, &Colormap, additivefog);
if (gltexture) gltexture->BindPatch(Colormap.colormap,translation);
if (gltexture) gltexture->BindPatch(Colormap.colormap, translation, OverrideShader);
else if (!modelframe) gl_RenderState.EnableTexture(false);
if (!modelframe)
@ -446,6 +450,9 @@ void GLSprite::Process(AActor* thing,sector_t * sector)
return;
}
// If this thing is in a map section that's not in view it can't possible be visible
if (!(currentmapsection[thing->subsector->mapsection>>3] & (1 << (thing->subsector->mapsection & 7)))) return;
// [RH] Interpolate the sprite's position to make it look smooth
fixed_t thingx = thing->PrevX + FixedMul (r_TicFrac, thing->x - thing->PrevX);
fixed_t thingy = thing->PrevY + FixedMul (r_TicFrac, thing->y - thing->PrevY);
@ -726,10 +733,30 @@ void GLSprite::Process(AActor* thing,sector_t * sector)
ThingColor=0xffffff;
RenderStyle = thing->RenderStyle;
RenderStyle.CheckFuzz();
OverrideShader = 0;
trans = FIXED2FLOAT(thing->alpha);
hw_styleflags = STYLEHW_Normal;
if (RenderStyle.BlendOp >= STYLEOP_Fuzz && RenderStyle.BlendOp <= STYLEOP_FuzzOrRevSub)
{
RenderStyle.CheckFuzz();
if (RenderStyle.BlendOp == STYLEOP_Fuzz)
{
if (gl.shadermodel >= 4 && gl_fuzztype != 0)
{
// Todo: implement shader selection here
RenderStyle = LegacyRenderStyles[STYLE_Translucent];
OverrideShader = gl_fuzztype + 4;
trans = 0.99f; // trans may not be 1 here
hw_styleflags |= STYLEHW_NoAlphaTest;
}
else
{
RenderStyle.BlendOp = STYLEOP_Shadow;
}
}
}
if (RenderStyle.Flags & STYLEF_TransSoulsAlpha)
{
trans = transsouls;
@ -739,7 +766,7 @@ void GLSprite::Process(AActor* thing,sector_t * sector)
trans = 1.f;
}
if (trans >= 1.f-FLT_EPSILON && RenderStyle.BlendOp != STYLEOP_Fuzz && (
if (trans >= 1.f-FLT_EPSILON && RenderStyle.BlendOp != STYLEOP_Shadow && (
(RenderStyle.SrcAlpha == STYLEALPHA_One && RenderStyle.DestAlpha == STYLEALPHA_Zero) ||
(RenderStyle.SrcAlpha == STYLEALPHA_Src && RenderStyle.DestAlpha == STYLEALPHA_InvSrc)
))
@ -774,7 +801,7 @@ void GLSprite::Process(AActor* thing,sector_t * sector)
if (enhancedvision && gl_enhanced_nightvision)
{
if (RenderStyle.BlendOp == STYLEOP_Fuzz)
if (RenderStyle.BlendOp == STYLEOP_Shadow)
{
// enhanced vision makes them more visible!
trans=0.5f;
@ -865,6 +892,7 @@ void GLSprite::ProcessParticle (particle_t *particle, sector_t *sector)//, int s
trans=particle->trans/255.0f;
RenderStyle = STYLE_Translucent;
OverrideShader = 0;
ThingColor = GPalette.BaseColors[particle->color];
ThingColor.a=0;

View file

@ -263,7 +263,7 @@ int gl_SetSpriteLighting(FRenderStyle style, AActor *thing, int lightlevel, int
cm->LightColor.r = cm->LightColor.g = cm->LightColor.b = gray;
}
if (style.BlendOp == STYLEOP_Fuzz)
if (style.BlendOp == STYLEOP_Shadow)
{
gl.Color4f(0.2f * ThingColor.r / 255.f, 0.2f * ThingColor.g / 255.f,
0.2f * ThingColor.b / 255.f, (alpha = 0.33f));

View file

@ -18,8 +18,8 @@ class ADynamicLight;
class FMaterial;
struct GLDrawList;
struct GLSkyInfo;
struct GLSectorStackInfo;
struct FTexCoordInfo;
struct FPortal;
enum WallTypes
@ -135,7 +135,7 @@ public:
AActor * skybox; // for skyboxes
GLSkyInfo * sky; // for normal sky
GLHorizonInfo * horizon; // for horizon information
GLSectorStackInfo * stack; // for sector stacks
FPortal * portal; // stacked sector portals
secplane_t * planemirror; // for plane mirrors
};
@ -163,12 +163,11 @@ private:
void FloodPlane(int pass);
void MirrorPlane(secplane_t * plane, bool ceiling);
void SkyTexture(int sky1,ASkyViewpoint * skyboxx, bool ceiling);
void SkyPlane(sector_t *sector, int plane, bool allowmirror);
void SkyNormal(sector_t * fs,vertex_t * v1,vertex_t * v2);
void SkyTop(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2);
void SkyBottom(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2);
void Put3DWall(lightlist_t * lightlist, bool translucent);
void SplitWall(sector_t * frontsector, bool translucent);
void LightPass();
@ -185,6 +184,7 @@ private:
int v_offset);
void DoMidTexture(seg_t * seg, bool drawfogboundary,
sector_t * front, sector_t * back,
sector_t * realfront, sector_t * realback,
fixed_t fch1, fixed_t fch2, fixed_t ffh1, fixed_t ffh2,
fixed_t bch1, fixed_t bch2, fixed_t bfh1, fixed_t bfh2);
@ -305,6 +305,7 @@ public:
FColormap Colormap;
FSpriteModelFrame * modelframe;
FRenderStyle RenderStyle;
int OverrideShader;
int translation;
int index;

View file

@ -214,9 +214,7 @@ void GLWall::PutWall(bool translucent)
case RENDERWALL_SECTORSTACK:
//@sync-portal
stack=UniqueStacks.Get(stack); // map all stacks with the same displacement together
portal=GLPortal::FindPortal(stack);
if (!portal) portal=new GLSectorStackPortal(stack);
portal = this->portal->GetGLPortal();
portal->AddLine(this);
break;
@ -246,7 +244,6 @@ void GLWall::PutWall(bool translucent)
case RENDERWALL_SKY:
//@sync-portal
sky=UniqueSkies.Get(sky);
portal=GLPortal::FindPortal(sky);
if (!portal) portal=new GLSkyPortal(sky);
portal->AddLine(this);
@ -505,7 +502,7 @@ bool GLWall::DoHorizon(seg_t * seg,sector_t * fs, vertex_t * v1,vertex_t * v2)
if (fs->GetTexture(sector_t::ceiling) == skyflatnum)
{
SkyTexture(fs->sky, fs->CeilingSkyBox, true);
SkyPlane(fs, sector_t::ceiling, false);
}
else
{
@ -534,7 +531,7 @@ bool GLWall::DoHorizon(seg_t * seg,sector_t * fs, vertex_t * v1,vertex_t * v2)
zbottom[1] = zbottom[0] = FIXED2FLOAT(fs->GetPlaneTexZ(sector_t::floor));
if (fs->GetTexture(sector_t::floor) == skyflatnum)
{
SkyTexture(fs->sky, fs->FloorSkyBox, false);
SkyPlane(fs, sector_t::floor, false);
}
else
{
@ -755,8 +752,7 @@ void GLWall::DoTexture(int _type,seg_t * seg, int peg,
gltexture->GetTexCoordInfo(&tci, seg->sidedef->GetTextureXScale(texpos), seg->sidedef->GetTextureYScale(texpos));
type = (seg->linedef->special == Line_Mirror && _type == RENDERWALL_M1S &&
!(gl.flags & RFL_NOSTENCIL) && gl_mirrors) ? RENDERWALL_MIRROR : _type;
type = (seg->linedef->special == Line_Mirror && _type == RENDERWALL_M1S && gl_mirrors) ? RENDERWALL_MIRROR : _type;
float floatceilingref = FIXED2FLOAT(ceilingrefheight) +
FIXED2FLOAT(tci.RowOffset(seg->sidedef->GetTextureYOffset(texpos))) +
@ -785,6 +781,7 @@ void GLWall::DoTexture(int _type,seg_t * seg, int peg,
//==========================================================================
void GLWall::DoMidTexture(seg_t * seg, bool drawfogboundary,
sector_t * front, sector_t * back,
sector_t * realfront, sector_t * realback,
fixed_t fch1, fixed_t fch2, fixed_t ffh1, fixed_t ffh2,
fixed_t bch1, fixed_t bch2, fixed_t bfh1, fixed_t bfh2)
@ -837,9 +834,18 @@ void GLWall::DoMidTexture(seg_t * seg, bool drawfogboundary,
FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::top));
if (!tex || tex->UseType==FTexture::TEX_Null)
{
// texture is missing - use the higher plane
topleft = MAX(bch1,fch1);
topright = MAX(bch2,fch2);
if (front->GetTexture(sector_t::ceiling) == skyflatnum &&
back->GetTexture(sector_t::ceiling) == skyflatnum)
{
// intra-sky lines do not clip the texture at all if there's no upper texture
topleft = topright = texturetop;
}
else
{
// texture is missing - use the higher plane
topleft = MAX(bch1,fch1);
topright = MAX(bch2,fch2);
}
}
else if ((bch1>fch1 || bch2>fch2) &&
(seg->frontsector->GetTexture(sector_t::ceiling)!=skyflatnum || seg->backsector->GetTexture(sector_t::ceiling)==skyflatnum))
@ -1436,7 +1442,7 @@ void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector)
#ifdef _MSC_VER
#ifdef _DEBUG
if (seg->linedef-lines==8)
if (seg->linedef-lines==1095)
__asm nop
#endif
#endif
@ -1545,7 +1551,7 @@ void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector)
}
if (seg->linedef->special==Line_Horizon && !(gl.flags&RFL_NOSTENCIL))
if (seg->linedef->special==Line_Horizon)
{
SkyNormal(frontsector,v1,v2);
DoHorizon(seg,frontsector, v1,v2);
@ -1648,7 +1654,8 @@ void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector)
gltexture=FMaterial::ValidateTexture(seg->sidedef->GetTexture(side_t::mid), true);
if (gltexture || drawfogboundary)
{
DoMidTexture(seg, drawfogboundary, realfront, realback, fch1, fch2, ffh1, ffh2, bch1, bch2, bfh1, bfh2);
DoMidTexture(seg, drawfogboundary, frontsector, backsector, realfront, realback,
fch1, fch2, ffh1, ffh2, bch1, bch2, bfh1, bfh2);
}
if (backsector->e->XFloor.ffloors.Size() || frontsector->e->XFloor.ffloors.Size())

View file

@ -57,6 +57,7 @@
EXTERN_CVAR (Bool, r_drawplayersprites)
EXTERN_CVAR(Float, transsouls)
EXTERN_CVAR (Bool, st_scale)
EXTERN_CVAR(Int, gl_fuzztype)
//==========================================================================
@ -65,7 +66,7 @@ EXTERN_CVAR (Bool, st_scale)
//
//==========================================================================
void FGLRenderer::DrawPSprite (player_t * player,pspdef_t *psp,fixed_t sx, fixed_t sy, int cm_index, bool hudModelStep)
void FGLRenderer::DrawPSprite (player_t * player,pspdef_t *psp,fixed_t sx, fixed_t sy, int cm_index, bool hudModelStep, int OverrideShader)
{
float fU1,fV1;
float fU2,fV2;
@ -91,7 +92,7 @@ void FGLRenderer::DrawPSprite (player_t * player,pspdef_t *psp,fixed_t sx, fixed
FMaterial * tex = FMaterial::ValidateTexture(lump, false);
if (!tex) return;
tex->BindPatch(cm_index, 0);
tex->BindPatch(cm_index, 0, OverrideShader);
int vw = viewwidth;
int vh = viewheight;
@ -144,7 +145,10 @@ void FGLRenderer::DrawPSprite (player_t * player,pspdef_t *psp,fixed_t sx, fixed
fV2=tex->GetVB();
}
if (tex->tex->gl_info.mIsTransparent) gl_RenderState.EnableAlphaTest(false);
if (tex->GetTransparent() || OverrideShader != 0)
{
gl_RenderState.EnableAlphaTest(false);
}
gl_RenderState.Apply();
gl.Begin(GL_TRIANGLE_STRIP);
gl.TexCoord2f(fU1, fV1); gl.Vertex2f(x1,y1);
@ -152,7 +156,10 @@ void FGLRenderer::DrawPSprite (player_t * player,pspdef_t *psp,fixed_t sx, fixed
gl.TexCoord2f(fU2, fV1); gl.Vertex2f(x2,y1);
gl.TexCoord2f(fU2, fV2); gl.Vertex2f(x2,y2);
gl.End();
if (tex->tex->gl_info.mIsTransparent) gl_RenderState.EnableAlphaTest(true);
if (tex->GetTransparent() || OverrideShader != 0)
{
gl_RenderState.EnableAlphaTest(true);
}
}
//==========================================================================
@ -264,10 +271,31 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
}
// Set the render parameters
vis.RenderStyle.CheckFuzz();
int OverrideShader = 0;
float trans = 0.f;
if (vis.RenderStyle.BlendOp >= STYLEOP_Fuzz && vis.RenderStyle.BlendOp <= STYLEOP_FuzzOrRevSub)
{
vis.RenderStyle.CheckFuzz();
if (vis.RenderStyle.BlendOp == STYLEOP_Fuzz)
{
if (gl.shadermodel >= 4 && gl_fuzztype != 0)
{
// Todo: implement shader selection here
vis.RenderStyle = LegacyRenderStyles[STYLE_Translucent];
OverrideShader = gl_fuzztype + 4;
trans = 0.99f; // trans may not be 1 here
}
else
{
vis.RenderStyle.BlendOp = STYLEOP_Shadow;
}
}
statebright[0] = statebright[1] = false;
}
gl_SetRenderStyle(vis.RenderStyle, false, false);
float trans;
if (vis.RenderStyle.Flags & STYLEF_TransSoulsAlpha)
{
trans = transsouls;
@ -276,7 +304,7 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
{
trans = 1.f;
}
else
else if (trans == 0.f)
{
trans = FIXED2FLOAT(vis.alpha);
}
@ -313,7 +341,7 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
// set the lighting parameters (only calls glColor and glAlphaFunc)
gl_SetSpriteLighting(vis.RenderStyle, playermo, statebright[i]? 255 : lightlevel,
0, &cmc, 0xffffff, trans, statebright[i], true);
DrawPSprite (player,psp,psp->sx+ofsx, psp->sy+ofsy, cm.colormap, hudModelStep);
DrawPSprite (player,psp,psp->sx+ofsx, psp->sy+ofsy, cm.colormap, hudModelStep, OverrideShader);
}
}
gl_RenderState.EnableBrightmap(false);
@ -344,5 +372,5 @@ void FGLRenderer::DrawTargeterSprites()
// The Targeter's sprites are always drawn normally.
for (i=ps_targetcenter, psp = &player->psprites[ps_targetcenter]; i<NUMPSPRITES; i++,psp++)
if (psp->state) DrawPSprite (player,psp,psp->sx, psp->sy, CM_DEFAULT, false);
if (psp->state) DrawPSprite (player,psp,psp->sx, psp->sy, CM_DEFAULT, false, 0);
}

View file

@ -389,6 +389,13 @@ static const FDefaultShader defaultshaders[]=
{"Warp 2", "shaders/glsl/func_warp2.fp"},
{"Brightmap","shaders/glsl/func_brightmap.fp"},
{"No Texture", "shaders/glsl/func_notexture.fp"},
{"Basic Fuzz", "shaders/glsl/fuzz_standard.fp"},
{"Smooth Fuzz", "shaders/glsl/fuzz_smooth.fp"},
{"Swirly Fuzz", "shaders/glsl/fuzz_swirly.fp"},
{"Translucent Fuzz", "shaders/glsl/fuzz_smoothtranslucent.fp"},
{"Jagged Fuzz", "shaders/glsl/fuzz_jagged.fp"},
{"Noise Fuzz", "shaders/glsl/fuzz_noise.fp"},
{"Smooth Noise Fuzz", "shaders/glsl/fuzz_smoothnoise.fp"},
{NULL,NULL}
};
@ -564,6 +571,17 @@ FShader *FShaderManager::BindEffect(int effect)
}
//==========================================================================
//
//
//
//==========================================================================
void gl_DestroyUserShaders()
{
// todo
}
//==========================================================================
//
// Parses a shader definition

View file

@ -131,7 +131,7 @@ class FShaderManager
void Clean();
void CompileShaders();
public:
FShaderManager();
~FShaderManager();

View file

@ -629,3 +629,12 @@ void OpenGLFrameBuffer::DrawRemainingPlayerSprites()
{
// not used by hardware renderer
}
void OpenGLFrameBuffer::GameRestart()
{
memcpy (SourcePalette, GPalette.BaseColors, sizeof(PalEntry)*256);
UpdatePalette ();
ScreenshotBuffer = NULL;
LastCamera = NULL;
gl_GenerateGlobalBrightmapFromColormap();
}

View file

@ -48,6 +48,7 @@ public:
int GetPageCount();
bool Begin2D(bool copy3d);
void GetHitlist(BYTE *hitlist);
void GameRestart();
// Retrieves a buffer containing image data for a screenshot.
// Hint: Pitch can be negative for upside-down images, in which case buffer

View file

@ -5,20 +5,17 @@ enum RenderFlags
{
RFL_NPOT_TEXTURE=1,
RFL_NOSTENCIL=2,
RFL_FRAGMENT_PROGRAM=4,
RFL_OCCLUSION_QUERY=16,
RFL_TEX_ENV_COMBINE4_NV=32,
RFL_TEX_ENV_COMBINE3_ATI=64,
RFL_OCCLUSION_QUERY=4,
// [BB] Added texture compression flags.
RFL_TEXTURE_COMPRESSION=128,
RFL_TEXTURE_COMPRESSION_S3TC=256,
RFL_TEXTURE_COMPRESSION=8,
RFL_TEXTURE_COMPRESSION_S3TC=16,
RFL_VBO = 512,
RFL_MAP_BUFFER_RANGE = 1024,
RFL_FRAMEBUFFER = 2048,
RFL_TEXTUREBUFFER = 4096,
RFL_NVIDIA = 8192,
RFL_ATI = 16384,
RFL_VBO = 32,
RFL_MAP_BUFFER_RANGE = 64,
RFL_FRAMEBUFFER = 128,
RFL_TEXTUREBUFFER = 256,
RFL_NVIDIA = 512,
RFL_ATI = 1024,
RFL_GL_20 = 0x10000000,

View file

@ -834,10 +834,10 @@ outl:
//
//===========================================================================
void FMaterial::Bind(int cm, int clampmode, int translation)
void FMaterial::Bind(int cm, int clampmode, int translation, int overrideshader)
{
int usebright = false;
int shaderindex = mShaderIndex;
int shaderindex = overrideshader > 0? overrideshader : mShaderIndex;
int maxbound = 0;
bool allowhires = tex->xScale == FRACUNIT && tex->yScale == FRACUNIT;
@ -848,7 +848,7 @@ void FMaterial::Bind(int cm, int clampmode, int translation)
else clampmode = 4;
const FHardwareTexture *gltexture = mBaseLayer->Bind(0, cm, clampmode, translation, allowhires? tex:NULL, softwarewarp);
if (gltexture != NULL && shaderindex > 0)
if (gltexture != NULL && shaderindex > 0 && overrideshader == 0)
{
for(unsigned i=0;i<mTextureLayers.Size();i++)
{
@ -882,10 +882,10 @@ void FMaterial::Bind(int cm, int clampmode, int translation)
//
//===========================================================================
void FMaterial::BindPatch(int cm, int translation)
void FMaterial::BindPatch(int cm, int translation, int overrideshader)
{
int usebright = false;
int shaderindex = mShaderIndex;
int shaderindex = overrideshader > 0? overrideshader : mShaderIndex;
int maxbound = 0;
int softwarewarp = gl_RenderState.SetupShader(tex->bHasCanvas, shaderindex, cm, tex->gl_info.shaderspeed);

View file

@ -134,8 +134,8 @@ public:
return !!mBaseLayer->tex->bMasked;
}
void Bind(int cm, int clamp=0, int translation=0);
void BindPatch(int cm, int translation=0);
void Bind(int cm, int clamp = 0, int translation = 0, int overrideshader = 0);
void BindPatch(int cm, int translation = 0, int overrideshader = 0);
unsigned char * CreateTexBuffer(int cm, int translation, int & w, int & h, bool expand = false, bool allowhires=true) const
{

View file

@ -132,6 +132,7 @@ FRemapTable GlobalBrightmap;
void gl_GenerateGlobalBrightmapFromColormap()
{
HasGlobalBrightmap = false;
int lump = Wads.CheckNumForName("COLORMAP");
if (lump == -1) lump = Wads.CheckNumForName("COLORMAP", ns_colormaps);
if (lump == -1) return;

View file

@ -52,6 +52,8 @@
#include "g_level.h"
extern void LoadActors ();
extern void InitBotStuff();
extern void ClearStrifeTypes();
//==========================================================================
@ -100,6 +102,7 @@ int GetSpriteIndex(const char * spritename)
void FActorInfo::StaticInit ()
{
sprites.Clear();
if (sprites.Size() == 0)
{
spritedef_t temp;
@ -120,7 +123,9 @@ void FActorInfo::StaticInit ()
}
Printf ("LoadActors: Load actor definitions.\n");
ClearStrifeTypes();
LoadActors ();
InitBotStuff();
}
//==========================================================================

View file

@ -110,10 +110,9 @@ void DIntermissionScreen::Init(FIntermissionAction *desc, bool first)
{
texname = GStrings[texname+1];
}
FTextureID tex = TexMan.CheckForTexture(texname, FTexture::TEX_MiscPatch);
if (tex.isValid())
if (texname[0] != 0)
{
mBackground = tex;
mBackground = TexMan.CheckForTexture(texname, FTexture::TEX_MiscPatch);
mFlatfill = desc->mFlatfill;
}
S_Sound (CHAN_VOICE | CHAN_UI, desc->mSound, 1.0f, ATTN_NONE);
@ -392,7 +391,12 @@ void DIntermissionScreenCast::Init(FIntermissionAction *desc, bool first)
mName = static_cast<FIntermissionActionCast*>(desc)->mName;
mClass = PClass::FindClass(static_cast<FIntermissionActionCast*>(desc)->mCastClass);
if (mClass != NULL) mDefaults = GetDefaultByType(mClass);
else mDefaults = NULL;
else
{
mDefaults = NULL;
caststate = NULL;
return;
}
mCastSounds.Resize(static_cast<FIntermissionActionCast*>(desc)->mCastSounds.Size());
for (unsigned i=0; i < mCastSounds.Size(); i++)
@ -405,15 +409,17 @@ void DIntermissionScreenCast::Init(FIntermissionAction *desc, bool first)
if (mClass->IsDescendantOf(RUNTIME_CLASS(APlayerPawn)))
{
advplayerstate = mDefaults->MissileState;
castsprite = skins[players[consoleplayer].userinfo.skin].sprite;
casttranslation = translationtables[TRANSLATION_Players][consoleplayer];
}
else
{
advplayerstate = NULL;
if (caststate != NULL) castsprite = caststate->sprite;
else castsprite = -1;
casttranslation = NULL;
if (mDefaults->Translation != 0)
{
casttranslation = translationtables[GetTranslationType(mDefaults->Translation)]
[GetTranslationIndex(mDefaults->Translation)];
}
}
castdeath = false;
castframes = 0;
@ -433,21 +439,26 @@ int DIntermissionScreenCast::Responder (event_t *ev)
return 1; // already in dying frames
castdeath = true;
caststate = mClass->ActorInfo->FindState(NAME_Death);
if (caststate == NULL) return -1;
casttics = caststate->GetTics();
castframes = 0;
castattacking = false;
if (mClass != NULL)
{
FName label[] = {NAME_Death, NAME_Cast};
caststate = mClass->ActorInfo->FindState(2, label);
if (caststate == NULL) return -1;
if (mClass->IsDescendantOf(RUNTIME_CLASS(APlayerPawn)))
{
int snd = S_FindSkinnedSound(players[consoleplayer].mo, "*death");
if (snd != 0) S_Sound (CHAN_VOICE | CHAN_UI, snd, 1, ATTN_NONE);
}
else if (mDefaults->DeathSound)
{
S_Sound (CHAN_VOICE | CHAN_UI, mDefaults->DeathSound, 1, ATTN_NONE);
casttics = caststate->GetTics();
castframes = 0;
castattacking = false;
if (mClass->IsDescendantOf(RUNTIME_CLASS(APlayerPawn)))
{
int snd = S_FindSkinnedSound(players[consoleplayer].mo, "*death");
if (snd != 0) S_Sound (CHAN_VOICE | CHAN_UI, snd, 1, ATTN_NONE);
}
else if (mDefaults->DeathSound)
{
S_Sound (CHAN_VOICE | CHAN_UI, mDefaults->DeathSound, 1, ATTN_NONE);
}
}
return true;
}
@ -478,7 +489,8 @@ int DIntermissionScreenCast::Ticker ()
if (--casttics > 0 && caststate != NULL)
return 0; // not time to change state yet
if (caststate == NULL || caststate->GetTics() == -1 || caststate->GetNextState() == NULL)
if (caststate == NULL || caststate->GetTics() == -1 || caststate->GetNextState() == NULL ||
(caststate->GetNextState() == caststate && castdeath))
{
return -1;
}
@ -494,7 +506,7 @@ int DIntermissionScreenCast::Ticker ()
castframes++;
}
if (castframes == 12)
if (castframes == 12 && !castdeath)
{
// go into attack frame
castattacking = true;
@ -559,6 +571,20 @@ void DIntermissionScreenCast::Drawer ()
// draw the current frame in the middle of the screen
if (caststate != NULL)
{
int castsprite;
if (!(mDefaults->flags4 & MF4_NOSKIN) &&
mDefaults->SpawnState != NULL && caststate->sprite == mDefaults->SpawnState->sprite &&
mClass->IsDescendantOf(RUNTIME_CLASS(APlayerPawn)) &&
skins != NULL)
{
castsprite = skins[players[consoleplayer].userinfo.skin].sprite;
}
else
{
castsprite = caststate->sprite;
}
sprframe = &SpriteFrames[sprites[castsprite].spriteframes + caststate->GetFrame()];
pic = TexMan(sprframe->Texture[0]);
@ -811,6 +837,7 @@ void F_StartIntermission(FIntermissionDescriptor *desc, bool deleteme, BYTE stat
viewactive = false;
automapactive = false;
DIntermissionController::CurrentIntermission = new DIntermissionController(desc, deleteme, state);
GC::WriteBarrier(DIntermissionController::CurrentIntermission);
}

View file

@ -80,6 +80,7 @@ struct FIntermissionAction
TArray<FIntermissionPatch> mOverlays;
FIntermissionAction();
virtual ~FIntermissionAction() {}
virtual bool ParseKey(FScanner &sc);
};
@ -145,7 +146,7 @@ struct FIntermissionActionScroller : public FIntermissionAction
struct FIntermissionDescriptor
{
FName mLink;
TArray<FIntermissionAction *> mActions;
TDeletingArray<FIntermissionAction *> mActions;
};
typedef TMap<FName, FIntermissionDescriptor*> FIntermissionDescriptorList;
@ -233,7 +234,6 @@ class DIntermissionScreenCast : public DIntermissionScreen
TArray<FICastSound> mCastSounds;
int casttics;
int castsprite; // [RH] For overriding the player sprite with a skin
const FRemapTable *casttranslation; // [RH] Draw "our hero" with their chosen suit color
FState* caststate;
FState* basestate;

View file

@ -47,6 +47,20 @@ static void ReplaceIntermission(FName intname,FIntermissionDescriptor *desc)
IntermissionDescriptors[intname] = desc;
}
void DeinitIntermissions()
{
FIntermissionDescriptorList::Iterator it(IntermissionDescriptors);
FIntermissionDescriptorList::Pair *pair;
while (it.NextPair(pair))
{
delete pair->Value;
pair->Value = NULL;
}
IntermissionDescriptors.Clear();
}
//==========================================================================
//
// FIntermissionAction
@ -820,7 +834,15 @@ void F_StartFinale (const char *music, int musicorder, int cdtrack, unsigned int
textscreen->mText << '$' << text;
}
textscreen->mTextDelay = 10;
textscreen->mBackground = flat;
if (flat != NULL && *flat != 0)
{
textscreen->mBackground = flat;
}
else
{
// force a black screen if no texture is set.
textscreen->mBackground = "-";
}
textscreen->mFlatfill = !finalePic;
if (music != NULL && *music != 0)

View file

@ -41,14 +41,16 @@
#include "c_bind.h"
#include "c_dispatch.h"
#include "gameconfigfile.h"
#include "w_wad.h"
TArray<FKeySection> KeySections;
extern TArray<FString> KeyConfWeapons;
static void LoadKeys (const char *modname, bool dbl)
{
char section[64];
mysnprintf (section, countof(section), "%s.%s%sBindings", gameinfo.ConfigName, modname,
mysnprintf (section, countof(section), "%s.%s%sBindings", gameinfo.ConfigName.GetChars(), modname,
dbl ? ".Double" : ".");
FKeyBindings *bindings = dbl? &DoubleBindings : &Bindings;
@ -141,3 +143,79 @@ CCMD (addmenukey)
}
}
//==========================================================================
//
// D_LoadWadSettings
//
// Parses any loaded KEYCONF lumps. These are restricted console scripts
// that can only execute the alias, defaultbind, addkeysection,
// addmenukey, weaponsection, and addslotdefault commands.
//
//==========================================================================
void D_LoadWadSettings ()
{
char cmd[4096];
int lump, lastlump = 0;
ParsingKeyConf = true;
KeySections.Clear();
KeyConfWeapons.Clear();
while ((lump = Wads.FindLump ("KEYCONF", &lastlump)) != -1)
{
FMemLump data = Wads.ReadLump (lump);
const char *eof = (char *)data.GetMem() + Wads.LumpLength (lump);
const char *conf = (char *)data.GetMem();
while (conf < eof)
{
size_t i;
// Fetch a line to execute
for (i = 0; conf + i < eof && conf[i] != '\n'; ++i)
{
cmd[i] = conf[i];
}
cmd[i] = 0;
conf += i;
if (*conf == '\n')
{
conf++;
}
// Comments begin with //
char *stop = cmd + i - 1;
char *comment = cmd;
int inQuote = 0;
if (*stop == '\r')
*stop-- = 0;
while (comment < stop)
{
if (*comment == '\"')
{
inQuote ^= 1;
}
else if (!inQuote && *comment == '/' && *(comment + 1) == '/')
{
break;
}
comment++;
}
if (comment == cmd)
{ // Comment at line beginning
continue;
}
else if (comment < stop)
{ // Comment in middle of line
*comment = 0;
}
AddCommandString (cmd);
}
}
ParsingKeyConf = false;
}

View file

@ -230,6 +230,26 @@ FString DArgs::TakeValue(const char *check)
return out;
}
//===========================================================================
//
// DArgs :: RemoveArg
//
//===========================================================================
void DArgs::RemoveArgs(const char *check)
{
int i = CheckParm(check);
if (i > 0 && i < (int)Argv.Size() - 1)
{
do
{
RemoveArg(i);
}
while (Argv[i][0] != '+' && Argv[i][0] != '-' && i < (int)Argv.Size() - 1);
}
}
//===========================================================================
//
// DArgs :: GetArg

View file

@ -54,6 +54,7 @@ public:
void AppendArg(FString arg);
void AppendArgs(int argc, const FString *argv);
void RemoveArg(int argindex);
void RemoveArgs(const char *check);
void SetArgs(int argc, char **argv);
void CollectFiles(const char *param, const char *extension);
DArgs *GatherFiles(const char *param) const;

View file

@ -139,5 +139,6 @@ inline SDWORD ModDiv (SDWORD num, SDWORD den, SDWORD *dmval)
#define FLOAT2FIXED(f) xs_Fix<16>::ToFix(f)
#define FIXED2FLOAT(f) ((f) / float(65536))
#define FIXED2DBL(f) ((f) / double(65536))
#endif

View file

@ -53,9 +53,10 @@
class DLoadSaveMenu : public DListMenu
{
DECLARE_CLASS(DLoadSaveMenu, DListMenu)
friend void ClearSaveGames();
protected:
static TDeletingArray<FSaveGameNode*> SaveGames;
static TArray<FSaveGameNode*> SaveGames;
static int LastSaved;
static int LastAccessed;
@ -114,7 +115,7 @@ public:
IMPLEMENT_CLASS(DLoadSaveMenu)
TDeletingArray<FSaveGameNode*> DLoadSaveMenu::SaveGames;
TArray<FSaveGameNode*> DLoadSaveMenu::SaveGames;
int DLoadSaveMenu::LastSaved = -1;
int DLoadSaveMenu::LastAccessed = -1;
@ -126,6 +127,21 @@ FSaveGameNode *quickSaveSlot;
//
//=============================================================================
void ClearSaveGames()
{
for(unsigned i=0;i<DLoadSaveMenu::SaveGames.Size(); i++)
{
delete DLoadSaveMenu::SaveGames[i];
}
DLoadSaveMenu::SaveGames.Clear();
}
//=============================================================================
//
// Save data maintenance (stored statically)
//
//=============================================================================
int DLoadSaveMenu::RemoveSaveSlot (int index)
{
FSaveGameNode *file = SaveGames[index];
@ -194,6 +210,8 @@ void DLoadSaveMenu::ReadSaveStrings ()
findstate_t c_file;
FString filter;
LastSaved = LastAccessed = -1;
quickSaveSlot = NULL;
filter = G_BuildSaveName ("*.zds", -1);
filefirst = I_FindFirst (filter.GetChars(), &c_file);
if (filefirst != ((void *)(-1)))

View file

@ -70,7 +70,6 @@ CVAR(Int, m_show_backbutton, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
DMenu *DMenu::CurrentMenu;
int DMenu::MenuTime;
FListMenuDescriptor *MainMenu;
FGameStartup GameStartupInfo;
EMenuState menuactive;
bool M_DemoNoPlay;
@ -544,7 +543,7 @@ bool M_Responder (event_t *ev)
}
}
}
else if (ev->type == EV_KeyDown || ev->type == EV_KeyUp)
else if (menuactive != MENU_WaitKey && (ev->type == EV_KeyDown || ev->type == EV_KeyUp))
{
keyup = ev->type == EV_KeyUp;

View file

@ -111,6 +111,22 @@ struct FListMenuDescriptor : public FMenuDescriptor
const PClass *mClass;
FMenuDescriptor *mRedirect; // used to redirect overlong skill and episode menus to option menu based alternatives
bool mCenter;
void Reset()
{
// Reset the default settings (ignore all other values in the struct)
mSelectOfsX = 0;
mSelectOfsY = 0;
mSelector.SetInvalid();
mDisplayTop = 0;
mXpos = 0;
mYpos = 0;
mLinespacing = 0;
mNetgameMessage = "";
mFont = NULL;
mFontColor = CR_UNTRANSLATED;
mFontColor2 = CR_UNTRANSLATED;
}
};
struct FOptionMenuSettings
@ -141,6 +157,14 @@ struct FOptionMenuDescriptor : public FMenuDescriptor
void CalcIndent();
FOptionMenuItem *GetItem(FName name);
void Reset()
{
// Reset the default settings (ignore all other values in the struct)
mPosition = 0;
mScrollTop = 0;
mIndent = 0;
mDontDim = 0;
}
};

View file

@ -52,6 +52,8 @@
#include "optionmenuitems.h"
void ClearSaveGames();
MenuDescriptorList MenuDescriptors;
static FListMenuDescriptor DefaultListMenuSettings; // contains common settings for all list menus
static FOptionMenuDescriptor DefaultOptionMenuSettings; // contains common settings for all Option menus
@ -83,7 +85,11 @@ static void DeinitMenus()
pair->Value = NULL;
}
}
MenuDescriptors.Clear();
OptionValues.Clear();
DMenu::CurrentMenu = NULL;
DefaultListMenuSettings.mItems.Clear();
ClearSaveGames();
}
//=============================================================================
@ -825,8 +831,11 @@ void M_ParseMenuDefs()
OptionSettings.mFontColorHeader = V_FindFontColor(gameinfo.mFontColorHeader);
OptionSettings.mFontColorHighlight = V_FindFontColor(gameinfo.mFontColorHighlight);
OptionSettings.mFontColorSelection = V_FindFontColor(gameinfo.mFontColorSelection);
DefaultListMenuSettings.Reset();
DefaultOptionMenuSettings.Reset();
atterm( DeinitMenus);
DeinitMenus();
while ((lump = Wads.FindLump ("MENUDEF", &lastlump)) != -1)
{
FScanner sc(lump);
@ -841,6 +850,10 @@ void M_ParseMenuDefs()
else if (sc.Compare("DEFAULTLISTMENU"))
{
ParseListMenuBody(sc, &DefaultListMenuSettings);
if (DefaultListMenuSettings.mItems.Size() > 0)
{
I_FatalError("You cannot add menu items to the menu default settings.");
}
}
else if (sc.Compare("OPTIONVALUE"))
{
@ -861,6 +874,10 @@ void M_ParseMenuDefs()
else if (sc.Compare("DEFAULTOPTIONMENU"))
{
ParseOptionMenuBody(sc, &DefaultOptionMenuSettings);
if (DefaultOptionMenuSettings.mItems.Size() > 0)
{
I_FatalError("You cannot add menu items to the menu default settings.");
}
}
else
{
@ -1221,10 +1238,11 @@ void M_CreateMenus()
// THe skill menu must be refeshed each time it starts up
//
//=============================================================================
extern int restart;
void M_StartupSkillMenu(FGameStartup *gs)
{
static bool done = false;
static int done = -1;
bool success = false;
FMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_Skillmenu);
if (desc != NULL)
@ -1250,9 +1268,9 @@ void M_StartupSkillMenu(FGameStartup *gs)
}
}
if (!done)
if (done != restart)
{
done = true;
done = restart;
int defskill = DefaultSkill;
if ((unsigned int)defskill >= AllSkills.Size())
{
@ -1327,7 +1345,7 @@ void M_StartupSkillMenu(FGameStartup *gs)
}
if (AllEpisodes[gs->Episode].mNoSkill || AllSkills.Size() == 1)
{
ld->mAutoselect = firstitem + MIN(2u, AllEpisodes.Size()-1);
ld->mAutoselect = firstitem + MIN(2u, AllSkills.Size()-1);
}
else
{

View file

@ -679,7 +679,7 @@ CCMD (quickload)
if (netgame)
{
M_StartMessage (GStrings("QLOADNET"), NULL);
M_StartMessage (GStrings("QLOADNET"), 1);
return;
}

View file

@ -891,13 +891,13 @@ public:
if (mkey == MKEY_Left)
{
if (--mSelection < 0) mSelection = mMaxValid;
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
return true;
}
else if (mkey == MKEY_Right)
{
if (++mSelection > mMaxValid) mSelection = 0;
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
return true;
}
else

View file

@ -115,23 +115,34 @@ bool FPlayerNameBox::GetString(int i, char *s, int len)
void FPlayerNameBox::DrawBorder (int x, int y, int len)
{
if (gameinfo.gametype & (GAME_DoomStrifeChex))
FTexture *left = TexMan[TexMan.CheckForTexture("M_LSLEFT", FTexture::TEX_MiscPatch)];
FTexture *mid = TexMan[TexMan.CheckForTexture("M_LSCNTR", FTexture::TEX_MiscPatch)];
FTexture *right = TexMan[TexMan.CheckForTexture("M_LSRGHT", FTexture::TEX_MiscPatch)];
if (left != NULL && right != NULL && mid != NULL)
{
int i;
screen->DrawTexture (TexMan["M_LSLEFT"], x-8, y+7, DTA_Clean, true, TAG_DONE);
screen->DrawTexture (left, x-8, y+7, DTA_Clean, true, TAG_DONE);
for (i = 0; i < len; i++)
{
screen->DrawTexture (TexMan["M_LSCNTR"], x, y+7, DTA_Clean, true, TAG_DONE);
screen->DrawTexture (mid, x, y+7, DTA_Clean, true, TAG_DONE);
x += 8;
}
screen->DrawTexture (TexMan["M_LSRGHT"], x, y+7, DTA_Clean, true, TAG_DONE);
screen->DrawTexture (right, x, y+7, DTA_Clean, true, TAG_DONE);
}
else
{
screen->DrawTexture (TexMan["M_FSLOT"], x, y+1, DTA_Clean, true, TAG_DONE);
FTexture *slot = TexMan[TexMan.CheckForTexture("M_FSLOT", FTexture::TEX_MiscPatch)];
if (slot != NULL)
{
screen->DrawTexture (slot, x, y+1, DTA_Clean, true, TAG_DONE);
}
else
{
screen->Clear(x, y, x + len, y + SmallFont->GetHeight() * 3/2, -1, 0);
}
}
}
@ -901,7 +912,7 @@ void DPlayerMenu::ClassChanged (FListMenuItem *li)
players[consoleplayer].userinfo.PlayerClass = sel-1;
PickPlayerClass();
cvar_set ("playerclass", sel == 0 ? "Random" : PlayerClass->Type->TypeName);
cvar_set ("playerclass", sel == 0 ? "Random" : PlayerClass->Type->Meta.GetMetaString (APMETA_DisplayName));
UpdateSkins();
UpdateColorsets();

View file

@ -105,12 +105,6 @@ xx(ArtiPoisonBag3)
// Strife quests
xx(QuestItem)
// Auto-usable health items
xx(ArtiHealth)
xx(ArtiSuperHealth)
xx(MedicalKit)
xx(MedPatch)
// Armor
xx(BasicArmor)
@ -251,6 +245,7 @@ xx(PoisonCloud) // makes monsters howl.
// a damage type if you wanted to force an extreme death.
xx(Extreme)
xx(MDK)
xx(Cast) // 'damage type' for the cast call
// Special names for thingdef_exp.cpp
xx(Random)
@ -285,6 +280,8 @@ xx(Communicator)
// Textmap properties
//xx(X)
//xx(Y)
xx(ZFloor)
xx(ZCeiling)
xx(Height)
//xx(Tid)
//xx(Angle)
@ -424,6 +421,8 @@ xx(Silent)
xx(Nofallingdamage)
xx(Dropactors)
xx(NoRespawn)
xx(Alphafloor)
xx(Alphaceiling)
xx(offsetx_top)
xx(offsety_top)

Some files were not shown because too many files have changed in this diff Show more