This commit is contained in:
nashmuhandes 2016-08-12 01:46:42 +08:00
commit 6abb6d8d51
82 changed files with 2967 additions and 1267 deletions

View file

@ -269,8 +269,10 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
set( CMAKE_C_FLAGS "-Wno-unused-result ${CMAKE_C_FLAGS}" )
set( CMAKE_CXX_FLAGS "-Wno-unused-result ${CMAKE_CXX_FLAGS}" )
endif()
if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set( CMAKE_CXX_FLAGS "-Wno-inconsistent-missing-override ${CMAKE_CXX_FLAGS}" )
if( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" )
if( APPLE OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "3.6" )
set( CMAKE_CXX_FLAGS "-Wno-inconsistent-missing-override ${CMAKE_CXX_FLAGS}" )
endif()
endif()
set( CMAKE_C_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_C_FLAGS}" )
set( CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_CXX_FLAGS}" )
@ -767,11 +769,13 @@ set( FASTMATH_SOURCES
gl/utility/gl_clock.cpp
gl/utility/gl_cycler.cpp
gl/utility/gl_geometric.cpp
gl/renderer/gl_2ddrawer.cpp
gl/renderer/gl_renderer.cpp
gl/renderer/gl_renderstate.cpp
gl/renderer/gl_renderbuffers.cpp
gl/renderer/gl_lightdata.cpp
gl/renderer/gl_postprocess.cpp
gl/renderer/gl_postprocessstate.cpp
gl/hqnx/init.cpp
gl/hqnx/hq2x.cpp
gl/hqnx/hq3x.cpp
@ -819,6 +823,7 @@ set( FASTMATH_SOURCES
gl/shaders/gl_bloomshader.cpp
gl/shaders/gl_blurshader.cpp
gl/shaders/gl_tonemapshader.cpp
gl/shaders/gl_lensshader.cpp
gl/system/gl_interface.cpp
gl/system/gl_framebuffer.cpp
gl/system/gl_menu.cpp

View file

@ -42,7 +42,7 @@ DEFINE_SPECIAL(Ceiling_LowerByValue, 40, 3, 5, 5)
DEFINE_SPECIAL(Ceiling_RaiseByValue, 41, 3, 4, 4)
DEFINE_SPECIAL(Ceiling_CrushAndRaise, 42, 3, 4, 4)
DEFINE_SPECIAL(Ceiling_LowerAndCrush, 43, 3, 4, 4)
DEFINE_SPECIAL(Ceiling_CrushStop, 44, 1, 1, 1)
DEFINE_SPECIAL(Ceiling_CrushStop, 44, 1, 2, 2)
DEFINE_SPECIAL(Ceiling_CrushRaiseAndStay, 45, 3, 4, 4)
DEFINE_SPECIAL(Floor_CrushStop, 46, 1, 1, 1)
DEFINE_SPECIAL(Ceiling_MoveToValue, 47, 3, 5, 5)
@ -59,7 +59,7 @@ DEFINE_SPECIAL(Sector_SetPortal, 57, -1, -1, 5)
DEFINE_SPECIAL(Sector_CopyScroller, 58, -1, -1, 2)
DEFINE_SPECIAL(Polyobj_OR_MoveToSpot, 59, 3, 3, 3)
DEFINE_SPECIAL(Plat_PerpetualRaise, 60, 3, 3, 3)
DEFINE_SPECIAL(Plat_Stop, 61, 1, 1, 1)
DEFINE_SPECIAL(Plat_Stop, 61, 1, 2, 2)
DEFINE_SPECIAL(Plat_DownWaitUpStay, 62, 3, 3, 3)
DEFINE_SPECIAL(Plat_DownByValue, 63, 4, 4, 4)
DEFINE_SPECIAL(Plat_UpWaitDownStay, 64, 3, 3, 3)
@ -176,7 +176,7 @@ DEFINE_SPECIAL(Sector_SetCeilingScale, 188, 5, 5, 5)
DEFINE_SPECIAL(Sector_SetFloorScale, 189, 5, 5, 5)
DEFINE_SPECIAL(Static_Init, 190, -1, -1, 4)
DEFINE_SPECIAL(SetPlayerProperty, 191, 3, 3, 3)
DEFINE_SPECIAL(Ceiling_LowerToHighestFloor, 192, 2, 4, 4)
DEFINE_SPECIAL(Ceiling_LowerToHighestFloor, 192, 2, 4, 5)
DEFINE_SPECIAL(Ceiling_LowerInstant, 193, 3, 5, 5)
DEFINE_SPECIAL(Ceiling_RaiseInstant, 194, 3, 4, 4)
DEFINE_SPECIAL(Ceiling_CrushRaiseAndStayA, 195, 4, 5, 5)
@ -222,7 +222,7 @@ DEFINE_SPECIAL(Light_MaxNeighbor, 234, 1, 1, 1)
DEFINE_SPECIAL(Floor_TransferTrigger, 235, 1, 1, 1)
DEFINE_SPECIAL(Floor_TransferNumeric, 236, 1, 1, 1)
DEFINE_SPECIAL(ChangeCamera, 237, 3, 3, 3)
DEFINE_SPECIAL(Floor_RaiseToLowestCeiling, 238, 2, 4, 4)
DEFINE_SPECIAL(Floor_RaiseToLowestCeiling, 238, 2, 4, 5)
DEFINE_SPECIAL(Floor_RaiseByValueTxTy, 239, 3, 3, 3)
DEFINE_SPECIAL(Floor_RaiseByTexture, 240, 2, 4, 4)
DEFINE_SPECIAL(Floor_LowerToLowestTxTy, 241, 2, 2, 2)
@ -238,21 +238,21 @@ DEFINE_SPECIAL(Floor_Donut, 250, 3, 3, 3)
DEFINE_SPECIAL(FloorAndCeiling_LowerRaise, 251, 3, 4, 4)
DEFINE_SPECIAL(Ceiling_RaiseToNearest, 252, 2, 3, 3)
DEFINE_SPECIAL(Ceiling_LowerToLowest, 253, 2, 4, 4)
DEFINE_SPECIAL(Ceiling_LowerToFloor, 254, 2, 4, 4)
DEFINE_SPECIAL(Ceiling_LowerToFloor, 254, 2, 4, 5)
DEFINE_SPECIAL(Ceiling_CrushRaiseAndStaySilA, 255, 4, 5, 5)
DEFINE_SPECIAL(Floor_LowerToHighestEE, 256, 2, 3, 3)
DEFINE_SPECIAL(Floor_RaiseToLowest, 257, 1, 3, 3)
DEFINE_SPECIAL(Floor_LowerToLowestCeiling, 258, 2, 3, 3)
DEFINE_SPECIAL(Floor_RaiseToCeiling, 259, 2, 4, 4)
DEFINE_SPECIAL(Floor_ToCeilingInstant, 260, 1, 3, 3)
DEFINE_SPECIAL(Floor_RaiseToCeiling, 259, 2, 4, 5)
DEFINE_SPECIAL(Floor_ToCeilingInstant, 260, 1, 3, 4)
DEFINE_SPECIAL(Floor_LowerByTexture, 261, 2, 3, 3)
DEFINE_SPECIAL(Ceiling_RaiseToHighest, 262, 2, 3, 3)
DEFINE_SPECIAL(Ceiling_ToHighestInstant, 263, 1, 3, 3)
DEFINE_SPECIAL(Ceiling_LowerToNearest, 264, 2, 4, 4)
DEFINE_SPECIAL(Ceiling_RaiseToLowest, 265, 2, 3, 3)
DEFINE_SPECIAL(Ceiling_RaiseToHighestFloor, 266, 2, 3, 3)
DEFINE_SPECIAL(Ceiling_ToFloorInstant, 267, 1, 3, 3)
DEFINE_SPECIAL(Ceiling_ToFloorInstant, 267, 1, 3, 4)
DEFINE_SPECIAL(Ceiling_RaiseByTexture, 268, 2, 3, 3)
DEFINE_SPECIAL(Ceiling_LowerByTexture, 269, 2, 4, 4)
DEFINE_SPECIAL(Stairs_BuildDownDoom, 270, 5, 5, 5)

View file

@ -1898,6 +1898,7 @@ void AM_drawSubsectors()
FDynamicColormap *colormap;
mpoint_t originpt;
screen->StartSimplePolys();
for (int i = 0; i < numsubsectors; ++i)
{
if (subsectors[i].flags & SSECF_POLYORG)
@ -2050,6 +2051,7 @@ void AM_drawSubsectors()
);
}
}
screen->FinishSimplePolys();
}
//=============================================================================

View file

@ -162,7 +162,7 @@ CVAR (Bool, con_centernotify, false, CVAR_ARCHIVE)
CUSTOM_CVAR (Int, con_scaletext, 0, CVAR_ARCHIVE) // Scale notify text at high resolutions?
{
if (self < 0) self = 0;
if (self > 2) self = 2;
if (self > 3) self = 3;
}
CUSTOM_CVAR(Float, con_alpha, 0.75f, CVAR_ARCHIVE)
@ -493,7 +493,14 @@ void C_AddNotifyString (int printlevel, const char *source)
return;
}
width = con_scaletext > 1 ? DisplayWidth/2 : con_scaletext == 1 ? DisplayWidth / CleanXfac : DisplayWidth;
switch (con_scaletext)
{
default:
case 0: width = DisplayWidth; break;
case 1: width = DisplayWidth / CleanXfac; break;
case 2: width = DisplayWidth / 2; break;
case 3: width = DisplayWidth / 4; break;
}
if (addtype == APPENDLINE && NotifyStrings[NUMNOTIFIES-1].PrintLevel == printlevel)
{
@ -770,6 +777,23 @@ static void C_DrawNotifyText ()
line, NotifyStrings[i].Text,
DTA_AlphaF, alpha, TAG_DONE);
}
else if (con_scaletext == 3)
{
if (!center)
screen->DrawText (SmallFont, color, 0, line, NotifyStrings[i].Text,
DTA_VirtualWidth, screen->GetWidth() / 4,
DTA_VirtualHeight, screen->GetHeight() / 4,
DTA_KeepRatio, true,
DTA_AlphaF, alpha, TAG_DONE);
else
screen->DrawText (SmallFont, color, (screen->GetWidth() / 4 -
SmallFont->StringWidth (NotifyStrings[i].Text))/4,
line, NotifyStrings[i].Text,
DTA_VirtualWidth, screen->GetWidth() / 4,
DTA_VirtualHeight, screen->GetHeight() / 4,
DTA_KeepRatio, true,
DTA_AlphaF, alpha, TAG_DONE);
}
else
{
if (!center)

View file

@ -109,8 +109,8 @@ static FCompatOption Options[] =
{ "ignoreteleporttags", BCOMPATF_BADTELEPORTERS, SLOT_BCOMPAT },
{ "rebuildnodes", BCOMPATF_REBUILDNODES, SLOT_BCOMPAT },
{ "linkfrozenprops", BCOMPATF_LINKFROZENPROPS, SLOT_BCOMPAT },
{ "disablepushwindowcheck", BCOMPATF_NOWINDOWCHECK, SLOT_BCOMPAT },
{ "floatbob", BCOMPATF_FLOATBOB, SLOT_BCOMPAT },
{ "noslopeid", BCOMPATF_NOSLOPEID, SLOT_BCOMPAT },
// list copied from g_mapinfo.cpp
{ "shorttex", COMPATF_SHORTTEX, SLOT_COMPAT },
@ -147,6 +147,8 @@ static FCompatOption Options[] =
{ "soundcutoff", COMPATF2_SOUNDCUTOFF, SLOT_COMPAT2 },
{ "pointonline", COMPATF2_POINTONLINE, SLOT_COMPAT2 },
{ "multiexit", COMPATF2_MULTIEXIT, SLOT_COMPAT2 },
{ "teleport", COMPATF2_TELEPORT, SLOT_COMPAT2 },
{ "disablepushwindowcheck", COMPATF2_PUSHWINDOW, SLOT_COMPAT2 },
{ NULL, 0, 0 }
};

View file

@ -234,9 +234,27 @@ void CT_Drawer (void)
scalex = 1;
}
int screen_width = con_scaletext > 1? SCREENWIDTH/2 : SCREENWIDTH;
int screen_height = con_scaletext > 1? SCREENHEIGHT/2 : SCREENHEIGHT;
int st_y = con_scaletext > 1? ST_Y/2 : ST_Y;
int screen_width, screen_height, st_y;
switch (con_scaletext)
{
default:
case 0:
case 1:
screen_width = SCREENWIDTH;
screen_height = SCREENHEIGHT;
st_y = ST_Y;
break;
case 2:
screen_width = SCREENWIDTH / 2;
screen_height = SCREENHEIGHT / 2;
st_y = ST_Y / 2;
break;
case 3:
screen_width = SCREENWIDTH / 4;
screen_height = SCREENHEIGHT / 4;
st_y = ST_Y / 4;
break;
}
y += ((SCREENHEIGHT == viewheight && viewactive) || gamestate != GS_LEVEL) ? screen_height : st_y;

View file

@ -575,7 +575,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
case 4: // Old ZDoom compat mode
v = COMPATF_SOUNDTARGET | COMPATF_LIGHT;
w = COMPATF2_MULTIEXIT;
w = COMPATF2_MULTIEXIT | COMPATF2_TELEPORT | COMPATF2_PUSHWINDOW;
break;
case 5: // MBF compat mode
@ -631,6 +631,8 @@ CVAR (Flag, compat_floormove, compatflags2, COMPATF2_FLOORMOVE);
CVAR (Flag, compat_soundcutoff, compatflags2, COMPATF2_SOUNDCUTOFF);
CVAR (Flag, compat_pointonline, compatflags2, COMPATF2_POINTONLINE);
CVAR (Flag, compat_multiexit, compatflags2, COMPATF2_MULTIEXIT);
CVAR (Flag, compat_teleport, compatflags2, COMPATF2_TELEPORT);
CVAR (Flag, compat_pushwindow, compatflags2, COMPATF2_PUSHWINDOW);
//==========================================================================
//

View file

@ -18,6 +18,7 @@ typedef std::pair<const class PType *, unsigned> FTypeAndOffset;
#define VARF_Method (1<<1) // func has an implied self parameter
#define VARF_Action (1<<2) // func has implied owner and state parameters
#define VARF_Native (1<<3) // func is native code/don't auto serialize field
#define VARF_ReadOnly (1<<4) // field is read only, do not write to it
// Symbol information -------------------------------------------------------

View file

@ -343,6 +343,8 @@ enum : unsigned int
COMPATF2_SOUNDCUTOFF = 1 << 2, // Cut off sounds when an actor vanishes instead of making it owner-less
COMPATF2_POINTONLINE = 1 << 3, // Use original but buggy P_PointOnLineSide() and P_PointOnDivlineSideCompat()
COMPATF2_MULTIEXIT = 1 << 4, // Level exit can be triggered multiple times (required by Daedalus's travel tubes, thanks to a faulty script)
COMPATF2_TELEPORT = 1 << 5, // Don't let indirect teleports trigger sector actions
COMPATF2_PUSHWINDOW = 1 << 6, // Disable the window check in CheckForPushSpecial()
};
// Emulate old bugs for select maps. These are not exposed by a cvar
@ -356,8 +358,8 @@ enum
BCOMPATF_BADPORTALS = 1 << 4, // Restores the old unstable portal behavior
BCOMPATF_REBUILDNODES = 1 << 5, // Force node rebuild
BCOMPATF_LINKFROZENPROPS = 1 << 6, // Clearing PROP_TOTALLYFROZEN or PROP_FROZEN also clears the other
BCOMPATF_NOWINDOWCHECK = 1 << 7, // Disable the window check in CheckForPushSpecial()
BCOMPATF_FLOATBOB = 1 << 8, // Use Hexen's original method of preventing floatbobbing items from falling down
BCOMPATF_NOSLOPEID = 1 << 9, // disable line IDs on slopes.
};
// phares 3/20/98:

View file

@ -1341,6 +1341,8 @@ MapFlagHandlers[] =
{ "compat_soundcutoff", MITYPE_COMPATFLAG, 0, COMPATF2_SOUNDCUTOFF },
{ "compat_pointonline", MITYPE_COMPATFLAG, 0, COMPATF2_POINTONLINE },
{ "compat_multiexit", MITYPE_COMPATFLAG, 0, COMPATF2_MULTIEXIT },
{ "compat_teleport", MITYPE_COMPATFLAG, 0, COMPATF2_TELEPORT },
{ "compat_pushwindow", MITYPE_COMPATFLAG, 0, COMPATF2_PUSHWINDOW },
{ "cd_start_track", MITYPE_EATNEXT, 0, 0 },
{ "cd_end1_track", MITYPE_EATNEXT, 0, 0 },
{ "cd_end2_track", MITYPE_EATNEXT, 0, 0 },

View file

@ -260,7 +260,14 @@ void DHUDMessage::ResetText (const char *text)
}
else
{
width = con_scaletext >= 2 ? SCREENWIDTH/2 : (con_scaletext ? SCREENWIDTH / CleanXfac : SCREENWIDTH);
switch (con_scaletext)
{
default:
case 0: width = SCREENWIDTH; break;
case 1: width = SCREENWIDTH / CleanXfac; break;
case 2: width = SCREENWIDTH / 2; break;
case 3: width = SCREENWIDTH / 4; break;
}
}
if (Lines != NULL)
@ -334,12 +341,18 @@ void DHUDMessage::Draw (int bottom, int visibility)
else
{
xscale = yscale = 1;
if (HUDWidth==0 && con_scaletext>1)
if (HUDWidth==0 && con_scaletext==2)
{
screen_width/=2;
screen_height/=2;
bottom/=2;
}
else if (HUDWidth==0 && con_scaletext==3)
{
screen_width/=4;
screen_height/=4;
bottom/=4;
}
}
if (HUDWidth == 0)
@ -448,6 +461,16 @@ void DHUDMessage::DoDraw (int linenum, int x, int y, bool clean, int hudheight)
DTA_RenderStyle, Style,
TAG_DONE);
}
else if (con_scaletext == 3)
{
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
DTA_VirtualWidth, SCREENWIDTH/4,
DTA_VirtualHeight, SCREENHEIGHT/4,
DTA_AlphaF, Alpha,
DTA_RenderStyle, Style,
DTA_KeepRatio, true,
TAG_DONE);
}
else
{
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
@ -551,6 +574,16 @@ void DHUDMessageFadeOut::DoDraw (int linenum, int x, int y, bool clean, int hudh
DTA_RenderStyle, Style,
TAG_DONE);
}
else if (con_scaletext == 3)
{
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
DTA_VirtualWidth, SCREENWIDTH/4,
DTA_VirtualHeight, SCREENHEIGHT/4,
DTA_AlphaF, trans,
DTA_RenderStyle, Style,
DTA_KeepRatio, true,
TAG_DONE);
}
else
{
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
@ -651,6 +684,16 @@ void DHUDMessageFadeInOut::DoDraw (int linenum, int x, int y, bool clean, int hu
DTA_RenderStyle, Style,
TAG_DONE);
}
else if (con_scaletext == 3)
{
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
DTA_VirtualWidth, SCREENWIDTH/4,
DTA_VirtualHeight, SCREENHEIGHT/4,
DTA_AlphaF, trans,
DTA_RenderStyle, Style,
DTA_KeepRatio, true,
TAG_DONE);
}
else
{
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
@ -830,6 +873,17 @@ void DHUDMessageTypeOnFadeOut::DoDraw (int linenum, int x, int y, bool clean, in
DTA_RenderStyle, Style,
TAG_DONE);
}
else if (con_scaletext == 3)
{
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,
DTA_VirtualWidth, SCREENWIDTH/4,
DTA_VirtualHeight, SCREENHEIGHT/4,
DTA_KeepRatio, true,
DTA_TextLen, LineVisible,
DTA_AlphaF, Alpha,
DTA_RenderStyle, Style,
TAG_DONE);
}
else
{
screen->DrawText (Font, TextColor, x, y, Lines[linenum].Text,

View file

@ -885,8 +885,25 @@ static void DrawCoordinates(player_t * CPlayer)
pos = DVector3(apos, z);
}
int vwidth = con_scaletext==0? SCREENWIDTH : SCREENWIDTH/2;
int vheight = con_scaletext==0? SCREENHEIGHT : SCREENHEIGHT/2;
int vwidth, vheight;
switch (con_scaletext)
{
default:
case 0:
vwidth = SCREENWIDTH;
vheight = SCREENHEIGHT;
break;
case 1:
case 2:
vwidth = SCREENWIDTH/2;
vheight = SCREENHEIGHT/2;
break;
case 3:
vwidth = SCREENWIDTH/4;
vheight = SCREENHEIGHT/4;
break;
}
int xpos = vwidth - SmallFont->StringWidth("X: -00000")-6;
int ypos = 18;
@ -1073,7 +1090,12 @@ void DrawHUD()
if (hud_althudscale && SCREENWIDTH>640)
{
hudwidth=SCREENWIDTH/2;
if (hud_althudscale == 2)
if (hud_althudscale == 3)
{
hudwidth = SCREENWIDTH / 4;
hudheight = SCREENHEIGHT / 4;
}
else if (hud_althudscale == 2)
{
// Optionally just double the pixels to reduce scaling artifacts.
hudheight=SCREENHEIGHT/2;

View file

@ -108,7 +108,7 @@ 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 (Float, crosshairscale, 1.0, CVAR_ARCHIVE);
CVAR (Bool, crosshairgrow, false, CVAR_ARCHIVE);
CUSTOM_CVAR(Int, am_showmaplabel, 2, CVAR_ARCHIVE)
{
@ -1106,9 +1106,9 @@ void DBaseStatusBar::DrawCrosshair ()
return;
}
if (crosshairscale)
if (crosshairscale > 0.0f)
{
size = SCREENHEIGHT / 200.;
size = SCREENHEIGHT * crosshairscale / 200.;
}
else
{
@ -1247,6 +1247,13 @@ void DBaseStatusBar::Draw (EHudState state)
xpos = vwidth - 80;
y = ::ST_Y - height;
}
else if (con_scaletext == 3)
{
vwidth = SCREENWIDTH/4;
vheight = SCREENHEIGHT/4;
xpos = vwidth - SmallFont->StringWidth("X: -00000")-6;
y = ::ST_Y/4 - height;
}
else
{
vwidth = SCREENWIDTH/2;
@ -1259,6 +1266,8 @@ void DBaseStatusBar::Draw (EHudState state)
{
if (con_scaletext == 0)
y -= height * 4;
else if (con_scaletext == 3)
y -= height;
else
y -= height * 2;
}
@ -1407,6 +1416,11 @@ void DBaseStatusBar::DrawLog ()
hudwidth = SCREENWIDTH / 2;
hudheight = SCREENHEIGHT / 2;
break;
case 3:
hudwidth = SCREENWIDTH / 4;
hudheight = SCREENHEIGHT / 4;
break;
}
int linelen = hudwidth<640? Scale(hudwidth,9,10)-40 : 560;

View file

@ -322,7 +322,7 @@ static void PrepareTransparentDoors(sector_t * sector)
sector_t * nextsec=NULL;
#ifdef _DEBUG
if (sector-sectors==2)
if (sector-sectors==34)
{
int a = 0;
}

View file

@ -71,16 +71,75 @@ FVertexBuffer::~FVertexBuffer()
}
}
void FSimpleVertexBuffer::BindVBO()
{
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
if (gl.glslversion > 0)
{
glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FSimpleVertex), &VSiO->x);
glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FSimpleVertex), &VSiO->u);
glVertexAttribPointer(VATTR_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof(FSimpleVertex), &VSiO->color);
glEnableVertexAttribArray(VATTR_VERTEX);
glEnableVertexAttribArray(VATTR_TEXCOORD);
glEnableVertexAttribArray(VATTR_COLOR);
glDisableVertexAttribArray(VATTR_VERTEX2);
}
else
{
glVertexPointer(3, GL_FLOAT, sizeof(FSimpleVertex), &VSiO->x);
glTexCoordPointer(2, GL_FLOAT, sizeof(FSimpleVertex), &VSiO->u);
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(FSimpleVertex), &VSiO->color);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
}
}
void FSimpleVertexBuffer::EnableColorArray(bool on)
{
if (on)
{
if (gl.glslversion > 0)
{
glEnableVertexAttribArray(VATTR_COLOR);
}
else
{
glEnableClientState(GL_COLOR_ARRAY);
}
}
else
{
if (gl.glslversion > 0)
{
glDisableVertexAttribArray(VATTR_COLOR);
}
else
{
glDisableClientState(GL_COLOR_ARRAY);
}
}
}
void FSimpleVertexBuffer::set(FSimpleVertex *verts, int count)
{
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
gl_RenderState.SetVertexBuffer(this);
glBufferData(GL_ARRAY_BUFFER, count * sizeof(*verts), verts, GL_STREAM_DRAW);
}
//==========================================================================
//
//
//
//==========================================================================
FFlatVertexBuffer::FFlatVertexBuffer()
: FVertexBuffer(!!(gl.flags & RFL_BUFFER_STORAGE))
FFlatVertexBuffer::FFlatVertexBuffer(int width, int height)
: FVertexBuffer(gl.buffermethod == BM_PERSISTENT)
{
if (gl.flags & RFL_BUFFER_STORAGE)
if (gl.buffermethod == BM_PERSISTENT)
{
unsigned int bytesize = BUFFER_SIZE * sizeof(FFlatVertex);
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
@ -91,19 +150,45 @@ FFlatVertexBuffer::FFlatVertexBuffer()
{
// The fallback path uses immediate mode rendering and does not set up an actual vertex buffer
vbo_shadowdata.Reserve(BUFFER_SIZE);
map = &vbo_shadowdata[0];
map = new FFlatVertex[BUFFER_SIZE];
}
mNumReserved = mIndex = mCurIndex = 0;
mIndex = mCurIndex = 0;
mNumReserved = 12;
vbo_shadowdata.Resize(mNumReserved);
// the first quad is reserved for handling coordinates through uniforms.
vbo_shadowdata[0].Set(1, 0, 0, 0, 0);
vbo_shadowdata[1].Set(2, 0, 0, 0, 0);
vbo_shadowdata[2].Set(3, 0, 0, 0, 0);
vbo_shadowdata[3].Set(4, 0, 0, 0, 0);
// and the second one for the fullscreen quad used for blend overlays.
vbo_shadowdata[4].Set(0, 0, 0, 0, 0);
vbo_shadowdata[5].Set(0, (float)height, 0, 0, 0);
vbo_shadowdata[6].Set((float)width, 0, 0, 0, 0);
vbo_shadowdata[7].Set((float)width, (float)height, 0, 0, 0);
// and this is for the postprocessing copy operation
vbo_shadowdata[8].Set(-1.0f, -1.0f, 0, 0.0f, 0.0f);
vbo_shadowdata[9].Set(-1.0f, 1.0f, 0, 0.0f, 1.f);
vbo_shadowdata[10].Set(1.0f, -1.0f, 0, 1.f, 0.0f);
vbo_shadowdata[11].Set(1.0f, 1.0f, 0, 1.f, 1.f);
}
FFlatVertexBuffer::~FFlatVertexBuffer()
{
if (gl.flags & RFL_BUFFER_STORAGE)
if (vbo_id != 0)
{
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
delete[] map;
}
map = nullptr;
}
@ -116,14 +201,15 @@ void FFlatVertexBuffer::BindVBO()
{
glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->x);
glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FFlatVertex), &VTO->u);
glEnableVertexAttribArray(VATTR_VERTEX);
glEnableVertexAttribArray(VATTR_TEXCOORD);
}
else
{
glDisableVertexAttribArray(VATTR_VERTEX);
glDisableVertexAttribArray(VATTR_TEXCOORD);
// If we cannot use a hardware buffer, use an old-style client array.
glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FFlatVertex), &map->x);
glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FFlatVertex), &map->u);
}
glEnableVertexAttribArray(VATTR_VERTEX);
glEnableVertexAttribArray(VATTR_TEXCOORD);
glDisableVertexAttribArray(VATTR_COLOR);
glDisableVertexAttribArray(VATTR_VERTEX2);
}
@ -135,40 +221,6 @@ void FFlatVertexBuffer::BindVBO()
}
}
//==========================================================================
//
// immediate mode fallback for drivers without GL_ARB_buffer_storage
//
// No single core method is performant enough to handle this adequately
// so we have to resort to immediate mode instead...
//
//==========================================================================
void FFlatVertexBuffer::ImmRenderBuffer(unsigned int primtype, unsigned int offset, unsigned int count)
{
// this will only get called if we can't acquire a persistently mapped buffer.
#ifndef CORE_PROFILE
glBegin(primtype);
if (gl.glslversion > 0)
{
for (unsigned int i = 0; i < count; i++)
{
glVertexAttrib2fv(VATTR_TEXCOORD, &map[offset + i].u);
glVertexAttrib3fv(VATTR_VERTEX, &map[offset + i].x);
}
}
else // no shader means no vertex attributes, so use the old stuff instead.
{
for (unsigned int i = 0; i < count; i++)
{
glTexCoord2fv(&map[offset + i].u);
glVertex3fv(&map[offset + i].x);
}
}
glEnd();
#endif
}
//==========================================================================
//
// Initialize a single vertex
@ -346,24 +398,10 @@ void FFlatVertexBuffer::UpdatePlaneVertices(sector_t *sec, int plane)
void FFlatVertexBuffer::CreateVBO()
{
if (gl.flags & RFL_BUFFER_STORAGE)
{
vbo_shadowdata.Resize(mNumReserved);
CreateFlatVBO();
mCurIndex = mIndex = vbo_shadowdata.Size();
memcpy(map, &vbo_shadowdata[0], vbo_shadowdata.Size() * sizeof(FFlatVertex));
}
else if (sectors)
{
// set all VBO info to invalid values so that we can save some checks in the rendering code
for(int i=0;i<numsectors;i++)
{
sectors[i].vboindex[3] = sectors[i].vboindex[2] =
sectors[i].vboindex[1] = sectors[i].vboindex[0] = -1;
sectors[i].vboheight[1] = sectors[i].vboheight[0] = FLT_MIN;
}
}
vbo_shadowdata.Resize(mNumReserved);
CreateFlatVBO();
mCurIndex = mIndex = vbo_shadowdata.Size();
memcpy(map, &vbo_shadowdata[0], vbo_shadowdata.Size() * sizeof(FFlatVertex));
}
//==========================================================================
@ -395,12 +433,9 @@ void FFlatVertexBuffer::CheckPlanes(sector_t *sector)
void FFlatVertexBuffer::CheckUpdate(sector_t *sector)
{
if (gl.flags & RFL_BUFFER_STORAGE)
{
CheckPlanes(sector);
sector_t *hs = sector->GetHeightSec();
if (hs != NULL) CheckPlanes(hs);
for (unsigned i = 0; i < sector->e->XFloor.ffloors.Size(); i++)
CheckPlanes(sector->e->XFloor.ffloors[i]->model);
}
CheckPlanes(sector);
sector_t *hs = sector->GetHeightSec();
if (hs != NULL) CheckPlanes(hs);
for (unsigned i = 0; i < sector->e->XFloor.ffloors.Size(); i++)
CheckPlanes(sector->e->XFloor.ffloors[i]->model);
}

View file

@ -36,11 +36,39 @@ struct FFlatVertex
u = uu;
v = vv;
}
void BindVBO();
};
struct FSimpleVertex
{
float x, z, y; // world position
float u, v; // texture coordinates
PalEntry color;
void Set(float xx, float zz, float yy, float uu = 0, float vv = 0, PalEntry col = 0xffffffff)
{
x = xx;
z = zz;
y = yy;
u = uu;
v = vv;
color = col;
}
};
#define VTO ((FFlatVertex*)NULL)
#define VSiO ((FSimpleVertex*)NULL)
class FSimpleVertexBuffer : public FVertexBuffer
{
TArray<FSimpleVertex> mBuffer;
public:
FSimpleVertexBuffer()
{
}
void BindVBO();
void set(FSimpleVertex *verts, int count);
void EnableColorArray(bool on);
};
class FFlatVertexBuffer : public FVertexBuffer
{
@ -54,12 +82,10 @@ class FFlatVertexBuffer : public FVertexBuffer
static const unsigned int BUFFER_SIZE = 2000000;
static const unsigned int BUFFER_SIZE_TO_USE = 1999500;
void ImmRenderBuffer(unsigned int primtype, unsigned int offset, unsigned int count);
public:
TArray<FFlatVertex> vbo_shadowdata; // this is kept around for updating the actual (non-readable) buffer and as stand-in for pre GL 4.x
FFlatVertexBuffer();
FFlatVertexBuffer(int width, int height);
~FFlatVertexBuffer();
void BindVBO();
@ -85,14 +111,7 @@ public:
void RenderArray(unsigned int primtype, unsigned int offset, unsigned int count)
{
drawcalls.Clock();
if (gl.flags & RFL_BUFFER_STORAGE)
{
glDrawArrays(primtype, offset, count);
}
else
{
ImmRenderBuffer(primtype, offset, count);
}
glDrawArrays(primtype, offset, count);
drawcalls.Unclock();
}
@ -105,16 +124,6 @@ public:
if (pcount) *pcount = count;
}
void RenderScreenQuad(float maxU = 1.0f, float maxV = 1.0f)
{
FFlatVertex *ptr = GetBuffer();
ptr->Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); ptr++;
ptr->Set(-1.0f, 1.0f, 0, 0.0f, maxV); ptr++;
ptr->Set(1.0f, -1.0f, 0, maxU, 0.0f); ptr++;
ptr->Set(1.0f, 1.0f, 0, maxU, maxV); ptr++;
RenderCurrent(ptr, GL_TRIANGLE_STRIP);
}
#endif
void Reset()
{
@ -146,6 +155,16 @@ struct FSkyVertex
color = col;
}
void SetXYZ(float xx, float yy, float zz, float uu = 0, float vv = 0, PalEntry col = 0xffffffff)
{
x = xx;
y = yy;
z = zz;
u = uu;
v = vv;
color = col;
}
};
class FSkyVertexBuffer : public FVertexBuffer
@ -167,6 +186,10 @@ private:
int mRows, mColumns;
// indices for sky cubemap faces
int mFaceStart[7];
int mSideStart;
void SkyVertex(int r, int c, bool yflip);
void CreateSkyHemisphere(int hemi);
void CreateDome();
@ -178,6 +201,11 @@ public:
virtual ~FSkyVertexBuffer();
void RenderDome(FMaterial *tex, int mode);
void BindVBO();
int FaceStart(int i)
{
if (i >= 0 && i < 7) return mFaceStart[i];
else return mSideStart;
}
};

View file

@ -71,7 +71,7 @@ FLightBuffer::FLightBuffer()
glGenBuffers(1, &mBufferId);
glBindBufferBase(mBufferType, LIGHTBUF_BINDINGPOINT, mBufferId);
glBindBuffer(mBufferType, mBufferId); // Note: Some older AMD drivers don't do that in glBindBufferBase, as they should.
if (gl.flags & RFL_BUFFER_STORAGE)
if (gl.lightmethod == LM_DIRECT)
{
glBufferStorage(mBufferType, mByteSize, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
@ -151,7 +151,7 @@ int FLightBuffer::UploadLights(FDynLightData &data)
// create the new buffer's storage (twice as large as the old one)
mBufferSize *= 2;
mByteSize *= 2;
if (gl.flags & RFL_BUFFER_STORAGE)
if (gl.lightmethod == LM_DIRECT)
{
glBufferStorage(mBufferType, mByteSize, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
@ -190,7 +190,7 @@ int FLightBuffer::UploadLights(FDynLightData &data)
void FLightBuffer::Begin()
{
if (!(gl.flags & RFL_BUFFER_STORAGE))
if (gl.lightmethod == LM_DEFERRED)
{
glBindBuffer(mBufferType, mBufferId);
mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT);
@ -199,7 +199,7 @@ void FLightBuffer::Begin()
void FLightBuffer::Finish()
{
if (!(gl.flags & RFL_BUFFER_STORAGE))
if (gl.lightmethod == LM_DEFERRED)
{
glBindBuffer(mBufferType, mBufferId);
glUnmapBuffer(mBufferType);

View file

@ -147,6 +147,6 @@ class CImage
char m_cBuf[32768];
};
#pragma pack(8)
#pragma pack()
}

View file

@ -0,0 +1,501 @@
/*
** gl_2ddrawer.h
** Container class for drawing 2d graphics with a vertex buffer
**
**---------------------------------------------------------------------------
** Copyright 2016 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
** covered by the terms of the GNU Lesser General Public License as published
** by the Free Software Foundation; either version 2.1 of the License, or (at
** your option) any later version.
** 5. Full disclosure of the entire project's source code, except for third
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "gl/system/gl_system.h"
#include "gl/system/gl_framebuffer.h"
#include "gl/renderer/gl_renderer.h"
#include "gl/renderer/gl_2ddrawer.h"
#include "gl/textures/gl_material.h"
#include "gl/renderer/gl_renderstate.h"
#include "gl/renderer/gl_lightdata.h"
#include "gl/scene/gl_drawinfo.h"
#include "gl/textures/gl_translate.h"
#include "vectors.h"
//==========================================================================
//
//
//
//==========================================================================
int F2DDrawer::AddData(const F2DDrawer::DataGeneric *data)
{
int addr = mData.Reserve(data->mLen);
memcpy(&mData[addr], data, data->mLen);
mLastLineCmd = -1;
return addr;
}
//==========================================================================
//
// Draws a texture
//
//==========================================================================
void F2DDrawer::AddTexture(FTexture *img, DrawParms &parms)
{
double xscale = parms.destwidth / parms.texwidth;
double yscale = parms.destheight / parms.texheight;
double x = parms.x - parms.left * xscale;
double y = parms.y - parms.top * yscale;
double w = parms.destwidth;
double h = parms.destheight;
float u1, v1, u2, v2;
int light = 255;
FMaterial * gltex = FMaterial::ValidateTexture(img, false);
if (gltex == nullptr) return;
DataTexture dg;
dg.mType = DrawTypeTexture;
dg.mLen = (sizeof(dg) + 7) & ~7;
dg.mVertCount = 4;
dg.mRenderStyle = parms.style;
dg.mMasked = !!parms.masked;
dg.mTexture = gltex;
if (parms.colorOverlay && (parms.colorOverlay & 0xffffff) == 0)
{
// handle black overlays as reduced light.
light = 255 - APART(parms.colorOverlay);
parms.colorOverlay = 0;
}
dg.mVertIndex = (int)mVertices.Reserve(parms.colorOverlay == 0? 4 : 8);
dg.mColorOverlay = parms.colorOverlay;
dg.mTranslation = 0;
if (!img->bHasCanvas)
{
if (!parms.alphaChannel)
{
if (parms.remap != NULL && !parms.remap->Inactive)
{
GLTranslationPalette * pal = static_cast<GLTranslationPalette*>(parms.remap->GetNative());
if (pal) dg.mTranslation = -pal->GetIndex();
}
}
dg.mAlphaTexture = !!(parms.style.Flags & STYLEF_RedIsAlpha);
u1 = gltex->GetUL();
v1 = gltex->GetVT();
u2 = gltex->GetUR();
v2 = gltex->GetVB();
}
else
{
dg.mAlphaTexture = false;
u1 = 0.f;
v1 = 1.f;
u2 = 1.f;
v2 = 0.f;
}
if (parms.flipX)
std::swap(u1, u2);
if (parms.windowleft > 0 || parms.windowright < parms.texwidth)
{
double wi = MIN(parms.windowright, parms.texwidth);
x += parms.windowleft * xscale;
w -= (parms.texwidth - wi + parms.windowleft) * xscale;
u1 = float(u1 + parms.windowleft / parms.texwidth);
u2 = float(u2 - (parms.texwidth - wi) / parms.texwidth);
}
PalEntry color;
if (parms.style.Flags & STYLEF_ColorIsFixed)
{
color = parms.fillcolor;
std::swap(color.r, color.b);
}
else
{
color = PalEntry(light, light, light);
}
color.a = (BYTE)(parms.Alpha * 255);
// scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates
int btm = (SCREENHEIGHT - screen->GetHeight()) / 2;
btm = SCREENHEIGHT - btm;
int space = (static_cast<OpenGLFrameBuffer*>(screen)->GetTrueHeight() - screen->GetHeight()) / 2;
dg.mScissor[0] = parms.lclip;
dg.mScissor[1] = btm - parms.dclip + space;
dg.mScissor[2] = parms.rclip - parms.lclip;
dg.mScissor[3] = parms.dclip - parms.uclip;
FSimpleVertex *ptr = &mVertices[dg.mVertIndex];
ptr->Set(x, y, 0, u1, v1, color); ptr++;
ptr->Set(x, y + h, 0, u1, v2, color); ptr++;
ptr->Set(x + w, y, 0, u2, v1, color); ptr++;
ptr->Set(x + w, y + h, 0, u2, v2, color); ptr++;
if (parms.colorOverlay != 0)
{
color = parms.colorOverlay;
std::swap(color.r, color.b);
ptr->Set(x, y, 0, u1, v1, color); ptr++;
ptr->Set(x, y + h, 0, u1, v2, color); ptr++;
ptr->Set(x + w, y, 0, u2, v1, color); ptr++;
ptr->Set(x + w, y + h, 0, u2, v2, color); ptr++;
}
AddData(&dg);
}
//==========================================================================
//
//
//
//==========================================================================
void F2DDrawer::AddPoly(FTexture *texture, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley,
DAngle rotation, FDynamicColormap *colormap, int lightlevel)
{
FMaterial *gltexture = FMaterial::ValidateTexture(texture, false);
if (gltexture == nullptr)
{
return;
}
DataSimplePoly poly;
poly.mType = DrawTypePoly;
poly.mLen = (sizeof(poly) + 7) & ~7;
poly.mTexture = gltexture;
poly.mColormap = colormap;
poly.mLightLevel = lightlevel;
poly.mVertCount = npoints;
poly.mVertIndex = (int)mVertices.Reserve(npoints);
bool dorotate = rotation != 0;
float cosrot = cos(rotation.Radians());
float sinrot = sin(rotation.Radians());
float uscale = float(1.f / (texture->GetScaledWidth() * scalex));
float vscale = float(1.f / (texture->GetScaledHeight() * scaley));
if (texture->bHasCanvas)
{
vscale = 0 - vscale;
}
float ox = float(originx);
float oy = float(originy);
for (int i = 0; i < npoints; ++i)
{
float u = points[i].X - 0.5f - ox;
float v = points[i].Y - 0.5f - oy;
if (dorotate)
{
float t = u;
u = t * cosrot - v * sinrot;
v = v * cosrot + t * sinrot;
}
mVertices[poly.mVertIndex+i].Set(points[i].X, points[i].Y, 0, u*uscale, v*vscale);
}
AddData(&poly);
}
//===========================================================================
//
//
//
//===========================================================================
void F2DDrawer::AddDim(PalEntry color, float damount, int x1, int y1, int w, int h)
{
color.a = uint8_t(damount * 255);
std::swap(color.r, color.b);
DataGeneric dg;
dg.mType = DrawTypeDim;
dg.mLen = (sizeof(dg) + 7) & ~7;
dg.mVertCount = 4;
dg.mVertIndex = (int)mVertices.Reserve(4);
FSimpleVertex *ptr = &mVertices[dg.mVertIndex];
ptr->Set(x1, y1, 0, 0, 0, color); ptr++;
ptr->Set(x1, y1 + h, 0, 0, 0, color); ptr++;
ptr->Set(x1 + w, y1 + h, 0, 0, 0, color); ptr++;
ptr->Set(x1 + w, y1, 0, 0, 0, color); ptr++;
AddData(&dg);
}
//==========================================================================
//
//
//
//==========================================================================
void F2DDrawer::AddClear(int left, int top, int right, int bottom, int palcolor, uint32 color)
{
PalEntry p = palcolor == -1 || color != 0 ? (PalEntry)color : GPalette.BaseColors[palcolor];
AddDim(p, 1.f, left, top, right - left, bottom - top);
}
//==========================================================================
//
//
//
//==========================================================================
void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin)
{
float fU1, fU2, fV1, fV2;
FMaterial *gltexture = FMaterial::ValidateTexture(src, false);
if (!gltexture) return;
DataFlatFill dg;
dg.mType = DrawTypeFlatFill;
dg.mLen = (sizeof(dg) + 7) & ~7;
dg.mVertCount = 4;
dg.mVertIndex = (int)mVertices.Reserve(4);
dg.mTexture = gltexture;
// scaling is not used here.
if (!local_origin)
{
fU1 = float(left) / src->GetWidth();
fV1 = float(top) / src->GetHeight();
fU2 = float(right) / src->GetWidth();
fV2 = float(bottom) / src->GetHeight();
}
else
{
fU1 = 0;
fV1 = 0;
fU2 = float(right - left) / src->GetWidth();
fV2 = float(bottom - top) / src->GetHeight();
}
FSimpleVertex *ptr = &mVertices[dg.mVertIndex];
ptr->Set(left, top, 0, fU1, fV1); ptr++;
ptr->Set(left, bottom, 0, fU1, fV2); ptr++;
ptr->Set(right, top, 0, fU2, fV1); ptr++;
ptr->Set(right, bottom, 0, fU2, fV2); ptr++;
AddData(&dg);
}
//==========================================================================
//
//
//
//==========================================================================
void F2DDrawer::AddLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color)
{
PalEntry p = color ? (PalEntry)color : GPalette.BaseColors[palcolor];
p.a = 255;
std::swap(p.r, p.b);
DataGeneric dg;
dg.mType = DrawTypeLine;
dg.mLen = (sizeof(dg) + 7) & ~7;
dg.mVertCount = 2;
dg.mVertIndex = (int)mVertices.Reserve(2);
mVertices[dg.mVertIndex].Set(x1, y1, 0, 0, 0, p);
mVertices[dg.mVertIndex+1].Set(x2, y2, 0, 0, 0, p);
// Test if we can batch multiple line commands
if (mLastLineCmd == -1)
{
mLastLineCmd = AddData(&dg);
}
else
{
DataGeneric *dg = (DataGeneric *)&mData[mLastLineCmd];
dg->mVertCount += 2;
}
}
//==========================================================================
//
//
//
//==========================================================================
void F2DDrawer::AddPixel(int x1, int y1, int palcolor, uint32 color)
{
PalEntry p = color ? (PalEntry)color : GPalette.BaseColors[palcolor];
p.a = 255;
std::swap(p.r, p.b);
DataGeneric dg;
dg.mType = DrawTypePixel;
dg.mLen = (sizeof(dg) + 7) & ~7;
dg.mVertCount = 2;
dg.mVertIndex = (int)mVertices.Reserve(1);
mVertices[dg.mVertIndex].Set(x1, y1, 0, 0, 0, p);
AddData(&dg);
}
//==========================================================================
//
//
//
//==========================================================================
void F2DDrawer::Flush()
{
F2DDrawer::EDrawType lasttype = DrawTypeTexture;
if (mData.Size() == 0) return;
SBYTE savedlightmode = glset.lightmode;
// lightmode is only relevant for automap subsectors,
// but We cannot use the software light mode here because it doesn't properly calculate the light for 2D rendering.
if (glset.lightmode == 8) glset.lightmode = 0;
set(&mVertices[0], mVertices.Size());
for (unsigned i = 0; i < mData.Size();)
{
DataGeneric *dg = (DataGeneric *)&mData[i];
// DrawTypePoly may not use the color part of the vertex buffer because it needs to use gl_SetColor to produce proper output.
if (lasttype == DrawTypePoly && dg->mType != DrawTypePoly)
{
EnableColorArray(true);
}
else if (lasttype != DrawTypePoly && dg->mType == DrawTypePoly)
{
EnableColorArray(false);
}
lasttype = dg->mType;
switch (dg->mType)
{
default:
break;
case DrawTypeTexture:
{
DataTexture *dt = static_cast<DataTexture*>(dg);
gl_SetRenderStyle(dt->mRenderStyle, !dt->mMasked, false);
gl_RenderState.SetMaterial(dt->mTexture, CLAMP_XY_NOMIP, dt->mTranslation, -1, dt->mAlphaTexture);
if (dt->mTexture->tex->bHasCanvas) gl_RenderState.SetTextureMode(TM_OPAQUE);
glEnable(GL_SCISSOR_TEST);
glScissor(dt->mScissor[0], dt->mScissor[1], dt->mScissor[2], dt->mScissor[3]);
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
gl_RenderState.Apply();
glDrawArrays(GL_TRIANGLE_STRIP, dt->mVertIndex, 4);
gl_RenderState.BlendEquation(GL_FUNC_ADD);
if (dt->mVertCount > 4)
{
gl_RenderState.SetTextureMode(TM_MASK);
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
gl_RenderState.Apply();
glDrawArrays(GL_TRIANGLE_STRIP, dt->mVertIndex + 4, 4);
}
glScissor(0, 0, screen->GetWidth(), screen->GetHeight());
glDisable(GL_SCISSOR_TEST);
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
gl_RenderState.SetTextureMode(TM_MODULATE);
break;
}
case DrawTypePoly:
{
DataSimplePoly *dsp = static_cast<DataSimplePoly*>(dg);
FColormap cm;
cm = dsp->mColormap;
gl_SetColor(dsp->mLightLevel, 0, cm, 1.f);
gl_RenderState.SetMaterial(dsp->mTexture, CLAMP_NONE, 0, -1, false);
gl_RenderState.Apply();
glDrawArrays(GL_TRIANGLE_FAN, dsp->mVertIndex, dsp->mVertCount);
break;
}
case DrawTypeFlatFill:
{
DataFlatFill *dff = static_cast<DataFlatFill*>(dg);
gl_RenderState.SetMaterial(dff->mTexture, CLAMP_NONE, 0, -1, false);
gl_RenderState.Apply();
glDrawArrays(GL_TRIANGLE_STRIP, dg->mVertIndex, dg->mVertCount);
break;
}
case DrawTypeDim:
gl_RenderState.EnableTexture(false);
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
gl_RenderState.AlphaFunc(GL_GREATER, 0);
gl_RenderState.Apply();
glDrawArrays(GL_TRIANGLE_FAN, dg->mVertIndex, dg->mVertCount);
gl_RenderState.EnableTexture(true);
break;
case DrawTypeLine:
gl_RenderState.EnableTexture(false);
gl_RenderState.Apply();
glDrawArrays(GL_LINES, dg->mVertIndex, dg->mVertCount);
gl_RenderState.EnableTexture(true);
break;
case DrawTypePixel:
gl_RenderState.EnableTexture(false);
gl_RenderState.Apply();
glDrawArrays(GL_POINTS, dg->mVertIndex, dg->mVertCount);
gl_RenderState.EnableTexture(true);
break;
}
i += dg->mLen;
}
mVertices.Clear();
mData.Clear();
gl_RenderState.SetVertexBuffer(GLRenderer->mVBO);
glset.lightmode = savedlightmode;
}

View file

@ -0,0 +1,73 @@
#ifndef __2DDRAWER_H
#define __2DDRAWER_H
#include "tarray.h"
#include "gl/data/gl_vertexbuffer.h"
class F2DDrawer : public FSimpleVertexBuffer
{
enum EDrawType
{
DrawTypeTexture,
DrawTypeDim,
DrawTypeFlatFill,
DrawTypePoly,
DrawTypeLine,
DrawTypePixel
};
struct DataGeneric
{
EDrawType mType;
uint32_t mLen;
int mVertIndex;
int mVertCount;
};
struct DataTexture : public DataGeneric
{
FMaterial *mTexture;
int mScissor[4];
uint32_t mColorOverlay;
int mTranslation;
FRenderStyle mRenderStyle;
bool mMasked;
bool mAlphaTexture;
};
struct DataFlatFill : public DataGeneric
{
FMaterial *mTexture;
};
struct DataSimplePoly : public DataGeneric
{
FMaterial *mTexture;
int mLightLevel;
FDynamicColormap *mColormap;
};
TArray<FSimpleVertex> mVertices;
TArray<uint8_t> mData;
int mLastLineCmd = -1; // consecutive lines can be batched into a single draw call so keep this info around.
int AddData(const DataGeneric *data);
public:
void AddTexture(FTexture *img, DrawParms &parms);
void AddDim(PalEntry color, float damount, int x1, int y1, int w, int h);
void AddClear(int left, int top, int right, int bottom, int palcolor, uint32 color);
void AddFlatFill(int left, int top, int right, int bottom, FTexture *src, bool local_origin);
void AddPoly(FTexture *texture, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley,
DAngle rotation, FDynamicColormap *colormap, int lightlevel);
void AddLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color);
void AddPixel(int x1, int y1, int palcolor, uint32 color);
void Flush();
};
#endif

View file

@ -63,12 +63,15 @@
#include "gl/renderer/gl_renderstate.h"
#include "gl/renderer/gl_renderbuffers.h"
#include "gl/renderer/gl_renderer.h"
#include "gl/renderer/gl_postprocessstate.h"
#include "gl/data/gl_data.h"
#include "gl/data/gl_vertexbuffer.h"
#include "gl/shaders/gl_bloomshader.h"
#include "gl/shaders/gl_blurshader.h"
#include "gl/shaders/gl_tonemapshader.h"
#include "gl/shaders/gl_lensshader.h"
#include "gl/shaders/gl_presentshader.h"
#include "gl/renderer/gl_2ddrawer.h"
//==========================================================================
//
@ -95,9 +98,23 @@ CUSTOM_CVAR(Int, gl_bloom_kernel_size, 7, 0)
self = 7;
}
CVAR(Bool, gl_lens, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Float, gl_lens_k, -0.12f, 0)
CVAR(Float, gl_lens_kcube, 0.1f, 0)
CVAR(Float, gl_lens_chromatic, 1.12f, 0)
EXTERN_CVAR(Float, vid_brightness)
EXTERN_CVAR(Float, vid_contrast)
void FGLRenderer::RenderScreenQuad()
{
mVBO->BindVBO();
gl_RenderState.ResetVertexBuffer();
glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
}
//-----------------------------------------------------------------------------
//
// Adds bloom contribution to scene texture
@ -110,47 +127,23 @@ void FGLRenderer::BloomScene()
if (!gl_bloom || !FGLRenderBuffers::IsEnabled() || gl_fixedcolormap != CM_DEFAULT)
return;
FGLPostProcessState savedState;
const float blurAmount = gl_bloom_amount;
int sampleCount = gl_bloom_kernel_size;
// TBD: Maybe need a better way to share state with other parts of the pipeline
GLint activeTex, textureBinding, samplerBinding;
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex);
glActiveTexture(GL_TEXTURE0);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding);
if (gl.flags & RFL_SAMPLER_OBJECTS)
{
glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding);
glBindSampler(0, 0);
}
GLboolean blendEnabled, scissorEnabled;
GLint currentProgram, blendEquationRgb, blendEquationAlpha, blendSrcRgb, blendSrcAlpha, blendDestRgb, blendDestAlpha;
glGetBooleanv(GL_BLEND, &blendEnabled);
glGetBooleanv(GL_SCISSOR_TEST, &scissorEnabled);
glGetIntegerv(GL_CURRENT_PROGRAM, &currentProgram);
glGetIntegerv(GL_BLEND_EQUATION_RGB, &blendEquationRgb);
glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &blendEquationAlpha);
glGetIntegerv(GL_BLEND_SRC_RGB, &blendSrcRgb);
glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrcAlpha);
glGetIntegerv(GL_BLEND_DST_RGB, &blendDestRgb);
glGetIntegerv(GL_BLEND_DST_ALPHA, &blendDestAlpha);
glDisable(GL_BLEND);
glDisable(GL_SCISSOR_TEST);
const auto &level0 = mBuffers->BloomLevels[0];
// Extract blooming pixels from scene texture:
glBindFramebuffer(GL_FRAMEBUFFER, level0.VFramebuffer);
glViewport(0, 0, level0.Width, level0.Height);
mBuffers->BindSceneTexture(0);
mBuffers->BindCurrentTexture(0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
mBloomExtractShader->Bind();
mBloomExtractShader->SceneTexture.Set(0);
mBloomExtractShader->Exposure.Set(mCameraExposure);
mVBO->BindVBO();
mVBO->RenderScreenQuad();
RenderScreenQuad();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -181,14 +174,14 @@ void FGLRenderer::BloomScene()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
mBloomCombineShader->Bind();
mBloomCombineShader->BloomTexture.Set(0);
mVBO->RenderScreenQuad();
RenderScreenQuad();
}
mBlurShader->BlurHorizontal(mVBO, blurAmount, sampleCount, level0.VTexture, level0.HFramebuffer, level0.Width, level0.Height);
mBlurShader->BlurVertical(mVBO, blurAmount, sampleCount, level0.HTexture, level0.VFramebuffer, level0.Width, level0.Height);
// Add bloom back to scene texture:
mBuffers->BindSceneTextureFB();
mBuffers->BindCurrentFB();
glViewport(mOutputViewport.left, mOutputViewport.top, mOutputViewport.width, mOutputViewport.height);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
@ -199,19 +192,7 @@ void FGLRenderer::BloomScene()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
mBloomCombineShader->Bind();
mBloomCombineShader->BloomTexture.Set(0);
mVBO->RenderScreenQuad();
if (blendEnabled)
glEnable(GL_BLEND);
if (scissorEnabled)
glEnable(GL_SCISSOR_TEST);
glBlendEquationSeparate(blendEquationRgb, blendEquationAlpha);
glBlendFuncSeparate(blendSrcRgb, blendDestRgb, blendSrcAlpha, blendDestAlpha);
glUseProgram(currentProgram);
glBindTexture(GL_TEXTURE_2D, textureBinding);
if (gl.flags & RFL_SAMPLER_OBJECTS)
glBindSampler(0, samplerBinding);
glActiveTexture(activeTex);
RenderScreenQuad();
}
//-----------------------------------------------------------------------------
@ -222,42 +203,72 @@ void FGLRenderer::BloomScene()
void FGLRenderer::TonemapScene()
{
if (gl_tonemap == 0)
if (gl_tonemap == 0 || !FGLRenderBuffers::IsEnabled())
return;
GLint activeTex, textureBinding, samplerBinding;
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex);
glActiveTexture(GL_TEXTURE0);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding);
if (gl.flags & RFL_SAMPLER_OBJECTS)
{
glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding);
glBindSampler(0, 0);
}
FGLPostProcessState savedState;
GLboolean blendEnabled, scissorEnabled;
glGetBooleanv(GL_BLEND, &blendEnabled);
glGetBooleanv(GL_SCISSOR_TEST, &scissorEnabled);
glDisable(GL_BLEND);
glDisable(GL_SCISSOR_TEST);
mBuffers->BindHudFB();
mBuffers->BindSceneTexture(0);
mBuffers->BindNextFB();
mBuffers->BindCurrentTexture(0);
mTonemapShader->Bind();
mTonemapShader->SceneTexture.Set(0);
mTonemapShader->Exposure.Set(mCameraExposure);
mVBO->BindVBO();
mVBO->RenderScreenQuad();
RenderScreenQuad();
mBuffers->NextTexture();
}
if (blendEnabled)
glEnable(GL_BLEND);
if (scissorEnabled)
glEnable(GL_SCISSOR_TEST);
glBindTexture(GL_TEXTURE_2D, textureBinding);
if (gl.flags & RFL_SAMPLER_OBJECTS)
glBindSampler(0, samplerBinding);
glActiveTexture(activeTex);
//-----------------------------------------------------------------------------
//
// Apply lens distortion and place the result in the HUD/2D texture
//
//-----------------------------------------------------------------------------
void FGLRenderer::LensDistortScene()
{
if (gl_lens == 0 || !FGLRenderBuffers::IsEnabled())
return;
float k[4] =
{
gl_lens_k,
gl_lens_k * gl_lens_chromatic,
gl_lens_k * gl_lens_chromatic * gl_lens_chromatic,
0.0f
};
float kcube[4] =
{
gl_lens_kcube,
gl_lens_kcube * gl_lens_chromatic,
gl_lens_kcube * gl_lens_chromatic * gl_lens_chromatic,
0.0f
};
float aspect = mOutputViewport.width / mOutputViewport.height;
// Scale factor to keep sampling within the input texture
float r2 = aspect * aspect * 0.25 + 0.25f;
float sqrt_r2 = sqrt(r2);
float f0 = 1.0f + MAX(r2 * (k[0] + kcube[0] * sqrt_r2), 0.0f);
float f2 = 1.0f + MAX(r2 * (k[2] + kcube[2] * sqrt_r2), 0.0f);
float f = MAX(f0, f2);
float scale = 1.0f / f;
FGLPostProcessState savedState;
mBuffers->BindNextFB();
mBuffers->BindCurrentTexture(0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
mLensShader->Bind();
mLensShader->InputTexture.Set(0);
mLensShader->AspectRatio.Set(aspect);
mLensShader->Scale.Set(scale);
mLensShader->LensDistortionCoefficient.Set(k);
mLensShader->CubicDistortionValue.Set(kcube);
RenderScreenQuad();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
mBuffers->NextTexture();
}
//-----------------------------------------------------------------------------
@ -268,25 +279,10 @@ void FGLRenderer::TonemapScene()
void FGLRenderer::CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma)
{
m2DDrawer->Flush(); // draw all pending 2D stuff before copying the buffer
if (FGLRenderBuffers::IsEnabled())
{
glDisable(GL_MULTISAMPLE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
GLboolean blendEnabled;
GLint currentProgram;
GLint activeTex, textureBinding, samplerBinding;
glGetBooleanv(GL_BLEND, &blendEnabled);
glGetIntegerv(GL_CURRENT_PROGRAM, &currentProgram);
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex);
glActiveTexture(GL_TEXTURE0);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding);
if (gl.flags & RFL_SAMPLER_OBJECTS)
{
glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding);
glBindSampler(0, 0);
}
FGLPostProcessState savedState;
mBuffers->BindOutputFB();
@ -356,16 +352,10 @@ void FGLRenderer::CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma)
mPresentShader->Contrast.Set(clamp<float>(vid_contrast, 0.1f, 3.f));
mPresentShader->Brightness.Set(clamp<float>(vid_brightness, -0.8f, 0.8f));
}
mBuffers->BindHudTexture(0);
mVBO->BindVBO();
mVBO->RenderScreenQuad(mScreenViewport.width / (float)mBuffers->GetWidth(), mScreenViewport.height / (float)mBuffers->GetHeight());
if (blendEnabled)
glEnable(GL_BLEND);
glUseProgram(currentProgram);
glBindTexture(GL_TEXTURE_2D, textureBinding);
if (gl.flags & RFL_SAMPLER_OBJECTS)
glBindSampler(0, samplerBinding);
glActiveTexture(activeTex);
mPresentShader->Scale.Set(mScreenViewport.width / (float)mBuffers->GetWidth(), mScreenViewport.height / (float)mBuffers->GetHeight());
mBuffers->BindCurrentTexture(0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
RenderScreenQuad();
}
}

View file

@ -0,0 +1,124 @@
/*
** gl_postprocessstate.cpp
** Render state maintenance
**
**---------------------------------------------------------------------------
** Copyright 2016 Magnus Norddahl
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
** covered by the terms of the GNU Lesser General Public License as published
** by the Free Software Foundation; either version 2.1 of the License, or (at
** your option) any later version.
** 5. Full disclosure of the entire project's source code, except for third
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "templates.h"
#include "gl/system/gl_system.h"
#include "gl/system/gl_interface.h"
#include "gl/data/gl_data.h"
#include "gl/data/gl_vertexbuffer.h"
#include "gl/system/gl_cvars.h"
#include "gl/shaders/gl_shader.h"
#include "gl/renderer/gl_renderer.h"
#include "gl/renderer/gl_postprocessstate.h"
//-----------------------------------------------------------------------------
//
// Saves state modified by post processing shaders
//
//-----------------------------------------------------------------------------
FGLPostProcessState::FGLPostProcessState()
{
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex);
glActiveTexture(GL_TEXTURE0);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding);
if (gl.flags & RFL_SAMPLER_OBJECTS)
{
glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding);
glBindSampler(0, 0);
}
glGetBooleanv(GL_BLEND, &blendEnabled);
glGetBooleanv(GL_SCISSOR_TEST, &scissorEnabled);
glGetBooleanv(GL_DEPTH_TEST, &depthEnabled);
glGetBooleanv(GL_MULTISAMPLE, &multisampleEnabled);
glGetIntegerv(GL_CURRENT_PROGRAM, &currentProgram);
glGetIntegerv(GL_BLEND_EQUATION_RGB, &blendEquationRgb);
glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &blendEquationAlpha);
glGetIntegerv(GL_BLEND_SRC_RGB, &blendSrcRgb);
glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrcAlpha);
glGetIntegerv(GL_BLEND_DST_RGB, &blendDestRgb);
glGetIntegerv(GL_BLEND_DST_ALPHA, &blendDestAlpha);
glDisable(GL_MULTISAMPLE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
}
//-----------------------------------------------------------------------------
//
// Restores state at the end of post processing
//
//-----------------------------------------------------------------------------
FGLPostProcessState::~FGLPostProcessState()
{
if (blendEnabled)
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
if (scissorEnabled)
glEnable(GL_SCISSOR_TEST);
else
glDisable(GL_SCISSOR_TEST);
if (depthEnabled)
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
if (multisampleEnabled)
glEnable(GL_MULTISAMPLE);
else
glDisable(GL_MULTISAMPLE);
glBlendEquationSeparate(blendEquationRgb, blendEquationAlpha);
glBlendFuncSeparate(blendSrcRgb, blendDestRgb, blendSrcAlpha, blendDestAlpha);
glUseProgram(currentProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureBinding);
if (gl.flags & RFL_SAMPLER_OBJECTS)
glBindSampler(0, samplerBinding);
glActiveTexture(activeTex);
}

View file

@ -0,0 +1,37 @@
#ifndef __GL_POSTPROCESSSTATE_H
#define __GL_POSTPROCESSSTATE_H
#include <string.h>
#include "gl/system/gl_interface.h"
#include "gl/data/gl_data.h"
#include "gl/data/gl_matrix.h"
#include "c_cvars.h"
#include "r_defs.h"
class FGLPostProcessState
{
public:
FGLPostProcessState();
~FGLPostProcessState();
private:
FGLPostProcessState(const FGLPostProcessState &) = delete;
FGLPostProcessState &operator=(const FGLPostProcessState &) = delete;
GLint activeTex;
GLint textureBinding;
GLint samplerBinding;
GLboolean blendEnabled;
GLboolean scissorEnabled;
GLboolean depthEnabled;
GLboolean multisampleEnabled;
GLint currentProgram;
GLint blendEquationRgb;
GLint blendEquationAlpha;
GLint blendSrcRgb;
GLint blendSrcAlpha;
GLint blendDestRgb;
GLint blendDestAlpha;
};
#endif

View file

@ -76,25 +76,26 @@ FGLRenderBuffers::FGLRenderBuffers()
FGLRenderBuffers::~FGLRenderBuffers()
{
ClearScene();
ClearHud();
ClearPipeline();
ClearBloom();
}
void FGLRenderBuffers::ClearScene()
{
DeleteFrameBuffer(mSceneFB);
DeleteFrameBuffer(mSceneTextureFB);
DeleteRenderBuffer(mSceneMultisample);
DeleteRenderBuffer(mSceneDepthStencil);
DeleteRenderBuffer(mSceneDepth);
DeleteRenderBuffer(mSceneStencil);
DeleteTexture(mSceneTexture);
}
void FGLRenderBuffers::ClearHud()
void FGLRenderBuffers::ClearPipeline()
{
DeleteFrameBuffer(mHudFB);
DeleteTexture(mHudTexture);
for (int i = 0; i < NumPipelineTextures; i++)
{
DeleteFrameBuffer(mPipelineFB[i]);
DeleteTexture(mPipelineTexture[i]);
}
}
void FGLRenderBuffers::ClearBloom()
@ -140,6 +141,9 @@ void FGLRenderBuffers::DeleteFrameBuffer(GLuint &handle)
void FGLRenderBuffers::Setup(int width, int height)
{
if (!IsEnabled())
return;
int samples = GetCvarSamples();
if (width == mWidth && height == mHeight && mSamples != samples)
@ -149,8 +153,8 @@ void FGLRenderBuffers::Setup(int width, int height)
}
else if (width > mWidth || height > mHeight)
{
CreatePipeline(width, height);
CreateScene(width, height, samples);
CreateHud(width, height);
CreateBloom(width, height);
mWidth = width;
mHeight = height;
@ -173,9 +177,6 @@ void FGLRenderBuffers::CreateScene(int width, int height, int samples)
{
ClearScene();
mSceneTexture = Create2DTexture(GetHdrFormat(), width, height);
mSceneTextureFB = CreateFrameBuffer(mSceneTexture);
if (samples > 1)
mSceneMultisample = CreateRenderBuffer(GetHdrFormat(), samples, width, height);
@ -183,26 +184,30 @@ void FGLRenderBuffers::CreateScene(int width, int height, int samples)
{
mSceneDepth = CreateRenderBuffer(GL_DEPTH_COMPONENT24, samples, width, height);
mSceneStencil = CreateRenderBuffer(GL_STENCIL_INDEX8, samples, width, height);
mSceneFB = CreateFrameBuffer(samples > 1 ? mSceneMultisample : mSceneTexture, mSceneDepth, mSceneStencil, samples > 1);
mSceneFB = CreateFrameBuffer(samples > 1 ? mSceneMultisample : mPipelineTexture[0], mSceneDepth, mSceneStencil, samples > 1);
}
else
{
mSceneDepthStencil = CreateRenderBuffer(GL_DEPTH24_STENCIL8, samples, width, height);
mSceneFB = CreateFrameBuffer(samples > 1 ? mSceneMultisample : mSceneTexture, mSceneDepthStencil, samples > 1);
mSceneFB = CreateFrameBuffer(samples > 1 ? mSceneMultisample : mPipelineTexture[0], mSceneDepthStencil, samples > 1);
}
}
//==========================================================================
//
// Creates the post-tonemapping-step buffers
// Creates the buffers needed for post processing steps
//
//==========================================================================
void FGLRenderBuffers::CreateHud(int width, int height)
void FGLRenderBuffers::CreatePipeline(int width, int height)
{
ClearHud();
mHudTexture = Create2DTexture(GetHdrFormat(), width, height);
mHudFB = CreateFrameBuffer(mHudTexture);
ClearPipeline();
for (int i = 0; i < NumPipelineTextures; i++)
{
mPipelineTexture[i] = Create2DTexture(GetHdrFormat(), width, height);
mPipelineFB[i] = CreateFrameBuffer(mPipelineTexture[i]);
}
}
//==========================================================================
@ -392,11 +397,13 @@ void FGLRenderBuffers::CheckFrameBufferCompleteness()
void FGLRenderBuffers::BlitSceneToTexture()
{
mCurrentPipelineTexture = 0;
if (mSamples <= 1)
return;
glBindFramebuffer(GL_READ_FRAMEBUFFER, mSceneFB);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mSceneTextureFB);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mPipelineFB[mCurrentPipelineTexture]);
glBlitFramebuffer(0, 0, mWidth, mHeight, 0, 0, mWidth, mHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
@ -415,27 +422,48 @@ void FGLRenderBuffers::BindSceneFB()
//==========================================================================
//
// Makes the scene texture frame buffer active (final 2D texture only)
// Binds the current scene/effect/hud texture to the specified texture unit
//
//==========================================================================
void FGLRenderBuffers::BindSceneTextureFB()
void FGLRenderBuffers::BindCurrentTexture(int index)
{
glBindFramebuffer(GL_FRAMEBUFFER, mSceneTextureFB);
glActiveTexture(GL_TEXTURE0 + index);
glBindTexture(GL_TEXTURE_2D, mPipelineFB[mCurrentPipelineTexture]);
}
//==========================================================================
//
// Makes the 2D/HUD frame buffer active
// Makes the frame buffer for the current texture active
//
//==========================================================================
void FGLRenderBuffers::BindHudFB()
void FGLRenderBuffers::BindCurrentFB()
{
if (gl_tonemap != 0)
glBindFramebuffer(GL_FRAMEBUFFER, mHudFB);
else
glBindFramebuffer(GL_FRAMEBUFFER, mSceneTextureFB);
glBindFramebuffer(GL_FRAMEBUFFER, mPipelineFB[mCurrentPipelineTexture]);
}
//==========================================================================
//
// Makes the frame buffer for the next texture active
//
//==========================================================================
void FGLRenderBuffers::BindNextFB()
{
int out = (mCurrentPipelineTexture + 1) % NumPipelineTextures;
glBindFramebuffer(GL_FRAMEBUFFER, mPipelineFB[out]);
}
//==========================================================================
//
// Next pipeline texture now contains the output
//
//==========================================================================
void FGLRenderBuffers::NextTexture()
{
mCurrentPipelineTexture = (mCurrentPipelineTexture + 1) % NumPipelineTextures;
}
//==========================================================================
@ -449,33 +477,6 @@ void FGLRenderBuffers::BindOutputFB()
glBindFramebuffer(GL_FRAMEBUFFER, mOutputFB);
}
//==========================================================================
//
// Binds the scene frame buffer texture to the specified texture unit
//
//==========================================================================
void FGLRenderBuffers::BindSceneTexture(int index)
{
glActiveTexture(GL_TEXTURE0 + index);
glBindTexture(GL_TEXTURE_2D, mSceneTexture);
}
//==========================================================================
//
// Binds the 2D/HUD frame buffer texture to the specified texture unit
//
//==========================================================================
void FGLRenderBuffers::BindHudTexture(int index)
{
glActiveTexture(GL_TEXTURE0 + index);
if (gl_tonemap != 0)
glBindTexture(GL_TEXTURE_2D, mHudTexture);
else
glBindTexture(GL_TEXTURE_2D, mSceneTexture);
}
//==========================================================================
//
// Returns true if render buffers are supported and should be used

View file

@ -21,13 +21,16 @@ public:
~FGLRenderBuffers();
void Setup(int width, int height);
void BlitSceneToTexture();
void BindSceneFB();
void BindSceneTextureFB();
void BindHudFB();
void BlitSceneToTexture();
void BindCurrentTexture(int index);
void BindCurrentFB();
void BindNextFB();
void NextTexture();
void BindOutputFB();
void BindSceneTexture(int index);
void BindHudTexture(int index);
enum { NumBloomLevels = 4 };
FGLBloomTextureLevel BloomLevels[NumBloomLevels];
@ -39,10 +42,10 @@ public:
private:
void ClearScene();
void ClearHud();
void ClearPipeline();
void ClearBloom();
void CreateScene(int width, int height, int samples);
void CreateHud(int width, int height);
void CreatePipeline(int width, int height);
void CreateBloom(int width, int height);
GLuint Create2DTexture(GLuint format, int width, int height);
GLuint CreateRenderBuffer(GLuint format, int width, int height);
@ -62,15 +65,21 @@ private:
int mHeight = 0;
int mSamples = 0;
GLuint mSceneTexture = 0;
static const int NumPipelineTextures = 2;
int mCurrentPipelineTexture = 0;
// Buffers for the scene
GLuint mSceneMultisample = 0;
GLuint mSceneDepthStencil = 0;
GLuint mSceneDepth = 0;
GLuint mSceneStencil = 0;
GLuint mSceneFB = 0;
GLuint mSceneTextureFB = 0;
GLuint mHudTexture = 0;
GLuint mHudFB = 0;
// Effect/HUD buffers
GLuint mPipelineTexture[NumPipelineTextures];
GLuint mPipelineFB[NumPipelineTextures];
// Back buffer frame buffer
GLuint mOutputFB = 0;
};

View file

@ -58,6 +58,7 @@
#include "gl/renderer/gl_lightdata.h"
#include "gl/renderer/gl_renderstate.h"
#include "gl/renderer/gl_renderbuffers.h"
#include "gl/renderer/gl_2ddrawer.h"
#include "gl/data/gl_data.h"
#include "gl/data/gl_vertexbuffer.h"
#include "gl/scene/gl_drawinfo.h"
@ -65,6 +66,7 @@
#include "gl/shaders/gl_bloomshader.h"
#include "gl/shaders/gl_blurshader.h"
#include "gl/shaders/gl_tonemapshader.h"
#include "gl/shaders/gl_lensshader.h"
#include "gl/shaders/gl_presentshader.h"
#include "gl/textures/gl_texture.h"
#include "gl/textures/gl_translate.h"
@ -105,19 +107,22 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb)
mShaderManager = NULL;
gllight = glpart2 = glpart = mirrortexture = NULL;
mLights = NULL;
m2DDrawer = nullptr;
}
void gl_LoadModels();
void gl_FlushModels();
void FGLRenderer::Initialize()
void FGLRenderer::Initialize(int width, int height)
{
mBuffers = new FGLRenderBuffers();
mBloomExtractShader = new FBloomExtractShader();
mBloomCombineShader = new FBloomCombineShader();
mBlurShader = new FBlurShader();
mTonemapShader = new FTonemapShader();
mLensShader = new FLensShader();
mPresentShader = new FPresentShader();
m2DDrawer = new F2DDrawer;
// Only needed for the core profile, because someone decided it was a good idea to remove the default VAO.
if (gl.version >= 4.0)
@ -132,7 +137,7 @@ void FGLRenderer::Initialize()
glpart = FTexture::CreateTexture(Wads.GetNumForFullName("glstuff/glpart.png"), FTexture::TEX_MiscPatch);
mirrortexture = FTexture::CreateTexture(Wads.GetNumForFullName("glstuff/mirror.png"), FTexture::TEX_MiscPatch);
mVBO = new FFlatVertexBuffer;
mVBO = new FFlatVertexBuffer(width, height);
mSkyVBO = new FSkyVertexBuffer;
if (gl.lightmethod != LM_SOFTWARE) mLights = new FLightBuffer();
else mLights = NULL;
@ -151,6 +156,7 @@ FGLRenderer::~FGLRenderer()
gl_FlushModels();
gl_DeleteAllAttachedLights();
FMaterial::FlushAll();
if (m2DDrawer != nullptr) delete m2DDrawer;
if (mShaderManager != NULL) delete mShaderManager;
if (mSamplerManager != NULL) delete mSamplerManager;
if (mVBO != NULL) delete mVBO;
@ -171,6 +177,7 @@ FGLRenderer::~FGLRenderer()
if (mBloomCombineShader) delete mBloomCombineShader;
if (mBlurShader) delete mBlurShader;
if (mTonemapShader) delete mTonemapShader;
if (mLensShader) delete mLensShader;
}
//==========================================================================
@ -248,7 +255,7 @@ void FGLRenderer::Begin2D()
if (mDrawingScene2D)
mBuffers->BindSceneFB();
else
mBuffers->BindHudFB();
mBuffers->BindCurrentFB();
}
glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
@ -375,366 +382,13 @@ void FGLRenderer::ClearBorders()
int borderHeight = (trueHeight - height) / 2;
glViewport(0, 0, width, trueHeight);
gl_RenderState.mProjectionMatrix.loadIdentity();
gl_RenderState.mProjectionMatrix.ortho(0.0f, width * 1.0f, 0.0f, trueHeight, -1.0f, 1.0f);
gl_RenderState.SetColor(0.f ,0.f ,0.f ,1.f);
gl_RenderState.Set2DMode(true);
gl_RenderState.EnableTexture(false);
gl_RenderState.Apply();
gl_RenderState.ApplyMatrices();
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(0, borderHeight, 0, 0, 0); ptr++;
ptr->Set(0, 0, 0, 0, 0); ptr++;
ptr->Set(width, 0, 0, 0, 0); ptr++;
ptr->Set(width, borderHeight, 0, 0, 0); ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
ptr->Set(0, trueHeight, 0, 0, 0); ptr++;
ptr->Set(0, trueHeight - borderHeight, 0, 0, 0); ptr++;
ptr->Set(width, trueHeight - borderHeight, 0, 0, 0); ptr++;
ptr->Set(width, trueHeight, 0, 0, 0); ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
gl_RenderState.EnableTexture(true);
glClearColor(0, 0, 0, 1);
glEnable(GL_SCISSOR_TEST);
glScissor(0, 0, width, borderHeight);
glClear(GL_COLOR_BUFFER_BIT);
glScissor(0, trueHeight-borderHeight, width, borderHeight);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_SCISSOR_TEST);
glViewport(0, (trueHeight - height) / 2, width, height);
}
//==========================================================================
//
// Draws a texture
//
//==========================================================================
void FGLRenderer::DrawTexture(FTexture *img, DrawParms &parms)
{
double xscale = parms.destwidth / parms.texwidth;
double yscale = parms.destheight / parms.texheight;
double x = parms.x - parms.left * xscale;
double y = parms.y - parms.top * yscale;
double w = parms.destwidth;
double h = parms.destheight;
float u1, v1, u2, v2;
int light = 255;
FMaterial * gltex = FMaterial::ValidateTexture(img, false);
if (parms.colorOverlay && (parms.colorOverlay & 0xffffff) == 0)
{
// Right now there's only black. Should be implemented properly later
light = 255 - APART(parms.colorOverlay);
parms.colorOverlay = 0;
}
gl_SetRenderStyle(parms.style, !parms.masked, false);
if (!img->bHasCanvas)
{
int translation = 0;
if (!parms.alphaChannel)
{
if (parms.remap != NULL && !parms.remap->Inactive)
{
GLTranslationPalette * pal = static_cast<GLTranslationPalette*>(parms.remap->GetNative());
if (pal) translation = -pal->GetIndex();
}
}
gl_RenderState.SetMaterial(gltex, CLAMP_XY_NOMIP, translation, -1, !!(parms.style.Flags & STYLEF_RedIsAlpha));
u1 = gltex->GetUL();
v1 = gltex->GetVT();
u2 = gltex->GetUR();
v2 = gltex->GetVB();
}
else
{
gl_RenderState.SetMaterial(gltex, CLAMP_XY_NOMIP, 0, -1, false);
u1 = 0.f;
v1 = 1.f;
u2 = 1.f;
v2 = 0.f;
gl_RenderState.SetTextureMode(TM_OPAQUE);
}
if (parms.flipX)
{
float temp = u1;
u1 = u2;
u2 = temp;
}
if (parms.windowleft > 0 || parms.windowright < parms.texwidth)
{
double wi = MIN(parms.windowright, parms.texwidth);
x += parms.windowleft * xscale;
w -= (parms.texwidth - wi + parms.windowleft) * xscale;
u1 = float(u1 + parms.windowleft / parms.texwidth);
u2 = float(u2 - (parms.texwidth - wi) / parms.texwidth);
}
PalEntry color;
if (parms.style.Flags & STYLEF_ColorIsFixed)
{
color = parms.fillcolor;
}
else
{
color = PalEntry(light, light, light);
}
color.a = (BYTE)(parms.Alpha * 255);
// scissor test doesn't use the current viewport for the coordinates, so use real screen coordinates
int btm = (SCREENHEIGHT - screen->GetHeight()) / 2;
btm = SCREENHEIGHT - btm;
glEnable(GL_SCISSOR_TEST);
int space = (static_cast<OpenGLFrameBuffer*>(screen)->GetTrueHeight()-screen->GetHeight())/2;
glScissor(parms.lclip, btm - parms.dclip + space, parms.rclip - parms.lclip, parms.dclip - parms.uclip);
gl_RenderState.SetColor(color);
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
gl_RenderState.Apply();
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(x, y, 0, u1, v1); ptr++;
ptr->Set(x, y + h, 0, u1, v2); ptr++;
ptr->Set(x + w, y, 0, u2, v1); ptr++;
ptr->Set(x + w, y + h, 0, u2, v2); ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
if (parms.colorOverlay)
{
gl_RenderState.SetTextureMode(TM_MASK);
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
gl_RenderState.BlendEquation(GL_FUNC_ADD);
gl_RenderState.SetColor(PalEntry(parms.colorOverlay));
gl_RenderState.Apply();
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(x, y, 0, u1, v1); ptr++;
ptr->Set(x, y + h, 0, u1, v2); ptr++;
ptr->Set(x + w, y, 0, u2, v1); ptr++;
ptr->Set(x + w, y + h, 0, u2, v2); ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
}
glScissor(0, 0, screen->GetWidth(), screen->GetHeight());
glDisable(GL_SCISSOR_TEST);
gl_RenderState.SetTextureMode(TM_MODULATE);
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
gl_RenderState.BlendEquation(GL_FUNC_ADD);
}
//==========================================================================
//
//
//
//==========================================================================
void FGLRenderer::DrawLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color)
{
PalEntry p = color? (PalEntry)color : GPalette.BaseColors[palcolor];
gl_RenderState.EnableTexture(false);
gl_RenderState.SetColorAlpha(p, 1.f);
gl_RenderState.Apply();
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(x1, y1, 0, 0, 0); ptr++;
ptr->Set(x2, y2, 0, 0, 0); ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_LINES);
gl_RenderState.EnableTexture(true);
}
//==========================================================================
//
//
//
//==========================================================================
void FGLRenderer::DrawPixel(int x1, int y1, int palcolor, uint32 color)
{
PalEntry p = color? (PalEntry)color : GPalette.BaseColors[palcolor];
gl_RenderState.EnableTexture(false);
gl_RenderState.SetColorAlpha(p, 1.f);
gl_RenderState.Apply();
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(x1, y1, 0, 0, 0); ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_POINTS);
gl_RenderState.EnableTexture(true);
}
//===========================================================================
//
//
//
//===========================================================================
void FGLRenderer::Dim(PalEntry color, float damount, int x1, int y1, int w, int h)
{
gl_RenderState.EnableTexture(false);
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
gl_RenderState.AlphaFunc(GL_GREATER,0);
gl_RenderState.SetColorAlpha(color, damount);
gl_RenderState.Apply();
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(x1, y1, 0, 0, 0); ptr++;
ptr->Set(x1, y1+h, 0, 0, 0); ptr++;
ptr->Set(x1+w, y1+h, 0, 0, 0); ptr++;
ptr->Set(x1+w, y1, 0, 0, 0); ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN);
gl_RenderState.EnableTexture(true);
}
//==========================================================================
//
//
//
//==========================================================================
void FGLRenderer::FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin)
{
float fU1,fU2,fV1,fV2;
FMaterial *gltexture=FMaterial::ValidateTexture(src, false);
if (!gltexture) return;
gl_RenderState.SetMaterial(gltexture, CLAMP_NONE, 0, -1, false);
// scaling is not used here.
if (!local_origin)
{
fU1 = float(left) / src->GetWidth();
fV1 = float(top) / src->GetHeight();
fU2 = float(right) / src->GetWidth();
fV2 = float(bottom) / src->GetHeight();
}
else
{
fU1 = 0;
fV1 = 0;
fU2 = float(right-left) / src->GetWidth();
fV2 = float(bottom-top) / src->GetHeight();
}
gl_RenderState.ResetColor();
gl_RenderState.Apply();
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(left, top, 0, fU1, fV1); ptr++;
ptr->Set(left, bottom, 0, fU1, fV2); ptr++;
ptr->Set(right, top, 0, fU2, fV1); ptr++;
ptr->Set(right, bottom, 0, fU2, fV2); ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
}
//==========================================================================
//
//
//
//==========================================================================
void FGLRenderer::Clear(int left, int top, int right, int bottom, int palcolor, uint32 color)
{
int rt;
int offY = 0;
PalEntry p = palcolor==-1 || color != 0? (PalEntry)color : GPalette.BaseColors[palcolor];
int width = right-left;
int height= bottom-top;
rt = screen->GetHeight() - top;
int space = (static_cast<OpenGLFrameBuffer*>(screen)->GetTrueHeight()-screen->GetHeight())/2; // ugh...
rt += space;
/*
if (!m_windowed && (m_trueHeight != m_height))
{
offY = (m_trueHeight - m_height) / 2;
rt += offY;
}
*/
glEnable(GL_SCISSOR_TEST);
glScissor(left, rt - height, width, height);
glClearColor(p.r/255.0f, p.g/255.0f, p.b/255.0f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.f, 0.f, 0.f, 0.f);
glDisable(GL_SCISSOR_TEST);
}
//==========================================================================
//
// D3DFB :: FillSimplePoly
//
// Here, "simple" means that a simple triangle fan can draw it.
//
//==========================================================================
void FGLRenderer::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley,
DAngle rotation, FDynamicColormap *colormap, int lightlevel)
{
if (npoints < 3)
{ // This is no polygon.
return;
}
FMaterial *gltexture = FMaterial::ValidateTexture(texture, false);
if (gltexture == NULL)
{
return;
}
FColormap cm;
cm = colormap;
// We cannot use the software light mode here because it doesn't properly calculate the light for 2D rendering.
SBYTE savedlightmode = glset.lightmode;
if (glset.lightmode == 8) glset.lightmode = 0;
gl_SetColor(lightlevel, 0, cm, 1.f);
glset.lightmode = savedlightmode;
gl_RenderState.SetMaterial(gltexture, CLAMP_NONE, 0, -1, false);
int i;
bool dorotate = rotation != 0;
float cosrot = cos(rotation.Radians());
float sinrot = sin(rotation.Radians());
//float yoffs = GatheringWipeScreen ? 0 : LBOffset;
float uscale = float(1.f / (texture->GetScaledWidth() * scalex));
float vscale = float(1.f / (texture->GetScaledHeight() * scaley));
if (gltexture->tex->bHasCanvas)
{
vscale = 0 - vscale;
}
float ox = float(originx);
float oy = float(originy);
gl_RenderState.Apply();
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
for (i = 0; i < npoints; ++i)
{
float u = points[i].X - 0.5f - ox;
float v = points[i].Y - 0.5f - oy;
if (dorotate)
{
float t = u;
u = t * cosrot - v * sinrot;
v = v * cosrot + t * sinrot;
}
ptr->Set(points[i].X, points[i].Y, 0, u*uscale, v*vscale);
ptr++;
}
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN);
}

View file

@ -23,7 +23,9 @@ class FBloomExtractShader;
class FBloomCombineShader;
class FBlurShader;
class FTonemapShader;
class FLensShader;
class FPresentShader;
class F2DDrawer;
inline float DEG2RAD(float deg)
{
@ -90,6 +92,7 @@ public:
FBloomCombineShader *mBloomCombineShader;
FBlurShader *mBlurShader;
FTonemapShader *mTonemapShader;
FLensShader *mLensShader;
FPresentShader *mPresentShader;
FTexture *gllight;
@ -105,6 +108,7 @@ public:
FFlatVertexBuffer *mVBO;
FSkyVertexBuffer *mSkyVBO;
FLightBuffer *mLights;
F2DDrawer *m2DDrawer;
GL_IRECT mScreenViewport;
GL_IRECT mOutputViewportLB;
@ -125,7 +129,7 @@ public:
void SetViewAngle(DAngle viewangle);
void SetupView(float viewx, float viewy, float viewz, DAngle viewangle, bool mirror, bool planemirror);
void Initialize();
void Initialize(int width, int height);
void CreateScene();
void RenderMultipassStuff();
@ -140,12 +144,6 @@ public:
void Begin2D();
void ClearBorders();
void DrawTexture(FTexture *img, DrawParms &parms);
void DrawLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color);
void DrawPixel(int x1, int y1, int palcolor, uint32 color);
void Dim(PalEntry color, float damount, int x1, int y1, int w, int h);
void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin);
void Clear(int left, int top, int right, int bottom, int palcolor, uint32 color);
void ProcessLowerMiniseg(seg_t *seg, sector_t * frontsector, sector_t * backsector);
void ProcessSprite(AActor *thing, sector_t *sector, bool thruportal);
@ -155,11 +153,13 @@ public:
unsigned char *GetTextureBuffer(FTexture *tex, int &w, int &h);
void SetupLevel();
void RenderScreenQuad();
void SetFixedColormap (player_t *player);
void WriteSavePic (player_t *player, FILE *file, int width, int height);
void EndDrawScene(sector_t * viewsector);
void BloomScene();
void TonemapScene();
void LensDistortScene();
void CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma);
void Flush() { CopyToBackbuffer(nullptr, true); }
@ -171,6 +171,9 @@ public:
bool StartOffscreen();
void EndOffscreen();
void StartSimplePolys();
void FinishSimplePolys();
void FillSimplePoly(FTexture *texture, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley,
DAngle rotation, FDynamicColormap *colormap, int lightlevel);

View file

@ -344,12 +344,12 @@ void FRenderState::SetClipHeight(float height, float direction)
mClipHeightDirection = direction;
#if 1
// This still doesn't work... :(
if (gl.glslversion < 1.3f) return;
if (gl.flags & RFL_NO_CLIP_PLANES) return;
#endif
if (direction != 0.f)
{
/*
if (gl.glslversion < 1.3f)
if (gl.flags & RFL_NO_CLIP_PLANES)
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();

View file

@ -237,7 +237,7 @@ public:
void EnableSplit(bool on)
{
if (gl.glslversion >= 1.3f)
if (!(gl.flags & RFL_NO_CLIP_PLANES))
{
mSplitEnabled = on;
if (on)
@ -260,7 +260,7 @@ public:
void EnableClipLine(bool on)
{
if (gl.glslversion >= 1.3f)
if (!(gl.flags & RFL_NO_CLIP_PLANES))
{
mClipLineEnabled = on;
if (on)

View file

@ -525,16 +525,8 @@ void gl_FillScreen()
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
gl_RenderState.EnableTexture(false);
gl_RenderState.Apply();
FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(0, 0, 0, 0, 0);
ptr++;
ptr->Set(0, (float)SCREENHEIGHT, 0, 0, 0);
ptr++;
ptr->Set((float)SCREENWIDTH, 0, 0, 0, 0);
ptr++;
ptr->Set((float)SCREENWIDTH, (float)SCREENHEIGHT, 0, 0, 0);
ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
// The fullscreen quad is stored at index 4 in the main vertex buffer.
glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
}
//==========================================================================
@ -864,6 +856,7 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo
if (FGLRenderBuffers::IsEnabled()) mBuffers->BlitSceneToTexture();
BloomScene();
TonemapScene();
LensDistortScene();
}
mDrawingScene2D = false;
eye->TearDown();

View file

@ -215,6 +215,72 @@ void FSkyVertexBuffer::CreateDome()
CreateSkyHemisphere(SKYHEMI_UPPER);
CreateSkyHemisphere(SKYHEMI_LOWER);
mPrimStart.Push(mVertices.Size());
mSideStart = mVertices.Size();
mFaceStart[0] = mSideStart + 10;
mFaceStart[1] = mFaceStart[0] + 4;
mFaceStart[2] = mFaceStart[1] + 4;
mFaceStart[3] = mFaceStart[2] + 4;
mFaceStart[4] = mFaceStart[3] + 4;
mFaceStart[5] = mFaceStart[4] + 4;
mFaceStart[6] = mFaceStart[5] + 4;
mVertices.Reserve(10 + 7*4);
FSkyVertex *ptr = &mVertices[mSideStart];
// all sides
ptr[0].SetXYZ(128.f, 128.f, -128.f, 0, 0);
ptr[1].SetXYZ(128.f, -128.f, -128.f, 0, 1);
ptr[2].SetXYZ(-128.f, 128.f, -128.f, 0.25f, 0);
ptr[3].SetXYZ(-128.f, -128.f, -128.f, 0.25f, 1);
ptr[4].SetXYZ(-128.f, 128.f, 128.f, 0.5f, 0);
ptr[5].SetXYZ(-128.f, -128.f, 128.f, 0.5f, 1);
ptr[6].SetXYZ(128.f, 128.f, 128.f, 0.75f, 0);
ptr[7].SetXYZ(128.f, -128.f, 128.f, 0.75f, 1);
ptr[8].SetXYZ(128.f, 128.f, -128.f, 1, 0);
ptr[9].SetXYZ(128.f, -128.f, -128.f, 1, 1);
// north face
ptr[10].SetXYZ(128.f, 128.f, -128.f, 0, 0);
ptr[11].SetXYZ(-128.f, 128.f, -128.f, 1, 0);
ptr[12].SetXYZ(128.f, -128.f, -128.f, 0, 1);
ptr[13].SetXYZ(-128.f, -128.f, -128.f, 1, 1);
// east face
ptr[14].SetXYZ(-128.f, 128.f, -128.f, 0, 0);
ptr[15].SetXYZ(-128.f, 128.f, 128.f, 1, 0);
ptr[16].SetXYZ(-128.f, -128.f, -128.f, 0, 1);
ptr[17].SetXYZ(-128.f, -128.f, 128.f, 1, 1);
// south face
ptr[18].SetXYZ(-128.f, 128.f, 128.f, 0, 0);
ptr[19].SetXYZ(128.f, 128.f, 128.f, 1, 0);
ptr[20].SetXYZ(-128.f, -128.f, 128.f, 0, 1);
ptr[21].SetXYZ(128.f, -128.f, 128.f, 1, 1);
// west face
ptr[22].SetXYZ(128.f, 128.f, 128.f, 0, 0);
ptr[23].SetXYZ(128.f, 128.f, -128.f, 1, 0);
ptr[24].SetXYZ(128.f, -128.f, 128.f, 0, 1);
ptr[25].SetXYZ(128.f, -128.f, -128.f, 1, 1);
// bottom face
ptr[26].SetXYZ(128.f, -128.f, -128.f, 0, 0);
ptr[27].SetXYZ(-128.f, -128.f, -128.f, 1, 0);
ptr[28].SetXYZ(128.f, -128.f, 128.f, 0, 1);
ptr[29].SetXYZ(-128.f, -128.f, 128.f, 1, 1);
// top face
ptr[30].SetXYZ(128.f, 128.f, -128.f, 0, 0);
ptr[31].SetXYZ(-128.f, 128.f, -128.f, 1, 0);
ptr[32].SetXYZ(128.f, 128.f, 128.f, 0, 1);
ptr[33].SetXYZ(-128.f, 128.f, 128.f, 1, 1);
// top face flipped
ptr[34].SetXYZ(128.f, 128.f, -128.f, 0, 1);
ptr[35].SetXYZ(-128.f, 128.f, -128.f, 1, 1);
ptr[36].SetXYZ(128.f, 128.f, 128.f, 0, 0);
ptr[37].SetXYZ(-128.f, 128.f, 128.f, 1, 0);
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
glBufferData(GL_ARRAY_BUFFER, mVertices.Size() * sizeof(FSkyVertex), &mVertices[0], GL_STATIC_DRAW);
}
@ -327,7 +393,6 @@ void RenderDome(FMaterial * tex, float x_offset, float y_offset, bool mirror, in
GLRenderer->mSkyVBO->RenderDome(tex, mode);
gl_RenderState.EnableTextureMatrix(false);
gl_RenderState.EnableModelMatrix(false);
}
@ -351,7 +416,6 @@ static void RenderBox(FTextureID texno, FMaterial * gltex, float x_offset, bool
else
gl_RenderState.mModelMatrix.rotate(-180.0f+x_offset, glset.skyrotatevector2.X, glset.skyrotatevector2.Z, glset.skyrotatevector2.Y);
FFlatVertex *ptr;
if (sb->faces[5])
{
faces=4;
@ -360,65 +424,25 @@ static void RenderBox(FTextureID texno, FMaterial * gltex, float x_offset, bool
tex = FMaterial::ValidateTexture(sb->faces[0], false);
gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false);
gl_RenderState.Apply();
ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(128.f, 128.f, -128.f, 0, 0);
ptr++;
ptr->Set(-128.f, 128.f, -128.f, 1, 0);
ptr++;
ptr->Set(128.f, -128.f, -128.f, 0, 1);
ptr++;
ptr->Set(-128.f, -128.f, -128.f, 1, 1);
ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
glDrawArrays(GL_TRIANGLE_STRIP, GLRenderer->mSkyVBO->FaceStart(0), 4);
// east
tex = FMaterial::ValidateTexture(sb->faces[1], false);
gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false);
gl_RenderState.Apply();
ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(-128.f, 128.f, -128.f, 0, 0);
ptr++;
ptr->Set(-128.f, 128.f, 128.f, 1, 0);
ptr++;
ptr->Set(-128.f, -128.f, -128.f, 0, 1);
ptr++;
ptr->Set(-128.f, -128.f, 128.f, 1, 1);
ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
glDrawArrays(GL_TRIANGLE_STRIP, GLRenderer->mSkyVBO->FaceStart(1), 4);
// south
tex = FMaterial::ValidateTexture(sb->faces[2], false);
gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false);
gl_RenderState.Apply();
ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(-128.f, 128.f, 128.f, 0, 0);
ptr++;
ptr->Set(128.f, 128.f, 128.f, 1, 0);
ptr++;
ptr->Set(-128.f, -128.f, 128.f, 0, 1);
ptr++;
ptr->Set(128.f, -128.f, 128.f, 1, 1);
ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
glDrawArrays(GL_TRIANGLE_STRIP, GLRenderer->mSkyVBO->FaceStart(2), 4);
// west
tex = FMaterial::ValidateTexture(sb->faces[3], false);
gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false);
gl_RenderState.Apply();
ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(128.f, 128.f, 128.f, 0, 0);
ptr++;
ptr->Set(128.f, 128.f, -128.f, 1, 0);
ptr++;
ptr->Set(128.f, -128.f, 128.f, 0, 1);
ptr++;
ptr->Set(128.f, -128.f, -128.f, 1, 1);
ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
glDrawArrays(GL_TRIANGLE_STRIP, GLRenderer->mSkyVBO->FaceStart(3), 4);
}
else
{
@ -426,62 +450,21 @@ static void RenderBox(FTextureID texno, FMaterial * gltex, float x_offset, bool
tex = FMaterial::ValidateTexture(sb->faces[0], false);
gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false);
gl_RenderState.Apply();
ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(128.f, 128.f, -128.f, 0, 0);
ptr++;
ptr->Set(128.f, -128.f, -128.f, 0, 1);
ptr++;
ptr->Set(-128.f, 128.f, -128.f, 0.25f, 0);
ptr++;
ptr->Set(-128.f, -128.f, -128.f, 0.25f, 1);
ptr++;
ptr->Set(-128.f, 128.f, 128.f, 0.5f, 0);
ptr++;
ptr->Set(-128.f, -128.f, 128.f, 0.5f, 1);
ptr++;
ptr->Set(128.f, 128.f, 128.f, 0.75f, 0);
ptr++;
ptr->Set(128.f, -128.f, 128.f, 0.75f, 1);
ptr++;
ptr->Set(128.f, 128.f, -128.f, 1, 0);
ptr++;
ptr->Set(128.f, -128.f, -128.f, 1, 1);
ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
glDrawArrays(GL_TRIANGLE_STRIP, GLRenderer->mSkyVBO->FaceStart(-1), 10);
}
// top
tex = FMaterial::ValidateTexture(sb->faces[faces], false);
gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false);
gl_RenderState.Apply();
ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(128.f, 128.f, -128.f, 0, sb->fliptop);
ptr++;
ptr->Set(-128.f, 128.f, -128.f, 1, sb->fliptop);
ptr++;
ptr->Set(128.f, 128.f, 128.f, 0, !sb->fliptop);
ptr++;
ptr->Set(-128.f, 128.f, 128.f, 1, !sb->fliptop);
ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
glDrawArrays(GL_TRIANGLE_STRIP, GLRenderer->mSkyVBO->FaceStart(sb->fliptop? 6:5), 4);
// bottom
tex = FMaterial::ValidateTexture(sb->faces[faces+1], false);
gl_RenderState.SetMaterial(tex, CLAMP_XY, 0, -1, false);
gl_RenderState.Apply();
glDrawArrays(GL_TRIANGLE_STRIP, GLRenderer->mSkyVBO->FaceStart(4), 4);
ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(128.f, -128.f, -128.f, 0, 0);
ptr++;
ptr->Set(-128.f, -128.f, -128.f, 1, 0);
ptr++;
ptr->Set(128.f, -128.f, 128.f, 0, 1);
ptr++;
ptr->Set(-128.f, -128.f, 128.f, 1, 1);
ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
gl_RenderState.EnableModelMatrix(false);
}
@ -512,13 +495,13 @@ void GLSkyPortal::DrawContents()
gl_MatrixStack.Push(gl_RenderState.mViewMatrix);
GLRenderer->SetupView(0, 0, 0, ViewAngle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1));
gl_RenderState.SetVertexBuffer(GLRenderer->mSkyVBO);
if (origin->texture[0] && origin->texture[0]->tex->gl_info.bSkybox)
{
RenderBox(origin->skytexno1, origin->texture[0], origin->x_offset[0], origin->sky2);
}
else
{
gl_RenderState.SetVertexBuffer(GLRenderer->mSkyVBO);
if (origin->texture[0]==origin->texture[1] && origin->doublesky) origin->doublesky=false;
if (origin->texture[0])
@ -547,11 +530,12 @@ void GLSkyPortal::DrawContents()
gl_RenderState.EnableTexture(true);
gl_RenderState.SetObjectColor(0xffffffff);
}
gl_RenderState.SetVertexBuffer(GLRenderer->mVBO);
}
gl_RenderState.SetVertexBuffer(GLRenderer->mVBO);
gl_MatrixStack.Pop(gl_RenderState.mViewMatrix);
gl_RenderState.ApplyMatrices();
glset.lightmode = oldlightmode;
gl_RenderState.SetDepthClamp(oldClamp);
gl_RenderState.EnableModelMatrix(false);
}

View file

@ -972,7 +972,7 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal)
if (thing->Sector->e->XFloor.lightlist.Size() != 0 && gl_fixedcolormap == CM_DEFAULT && !fullbright &&
RenderStyle.BlendOp != STYLEOP_Shadow && RenderStyle.BlendOp != STYLEOP_RevSub)
{
if (gl.glslversion < 1.3) // on old hardware we are rather limited...
if (gl.flags & RFL_NO_CLIP_PLANES) // on old hardware we are rather limited...
{
lightlist = NULL;
if (!drawWithXYBillboard && !modelframe)

View file

@ -187,7 +187,7 @@ private:
void RenderLightsCompat(int pass);
void Put3DWall(lightlist_t * lightlist, bool translucent);
void SplitWallComplex(sector_t * frontsector, bool translucent, float maplightbottomleft, float maplightbottomright);
bool SplitWallComplex(sector_t * frontsector, bool translucent, float& maplightbottomleft, float& maplightbottomright);
void SplitWall(sector_t * frontsector, bool translucent);
void SetupLights();

View file

@ -264,7 +264,7 @@ void GLWall::Put3DWall(lightlist_t * lightlist, bool translucent)
//
//==========================================================================
void GLWall::SplitWallComplex(sector_t * frontsector, bool translucent, float maplightbottomleft, float maplightbottomright)
bool GLWall::SplitWallComplex(sector_t * frontsector, bool translucent, float& maplightbottomleft, float& maplightbottomright)
{
GLWall copyWall1, copyWall2;
@ -304,7 +304,7 @@ void GLWall::SplitWallComplex(sector_t * frontsector, bool translucent, float ma
copyWall1.SplitWall(frontsector, translucent);
copyWall2.SplitWall(frontsector, translucent);
return;
return true;
}
}
@ -345,9 +345,11 @@ void GLWall::SplitWallComplex(sector_t * frontsector, bool translucent, float ma
copyWall1.SplitWall(frontsector, translucent);
copyWall2.SplitWall(frontsector, translucent);
return;
return true;
}
}
return false;
}
void GLWall::SplitWall(sector_t * frontsector, bool translucent)
@ -401,19 +403,19 @@ void GLWall::SplitWall(sector_t * frontsector, bool translucent)
(maplightbottomleft<zbottom[0] && maplightbottomright>zbottom[1]) ||
(maplightbottomleft > zbottom[0] && maplightbottomright < zbottom[1]))
{
if (gl.glslversion >= 1.3f)
if (!(gl.flags & RFL_NO_CLIP_PLANES))
{
// Use hardware clipping if this cannot be done cleanly.
this->lightlist = &lightlist;
PutWall(translucent);
}
else
{
// crappy fallback if no clip planes available
SplitWallComplex(frontsector, translucent, maplightbottomleft, maplightbottomright);
}
goto out;
goto out;
}
// crappy fallback if no clip planes available
else if (SplitWallComplex(frontsector, translucent, maplightbottomleft, maplightbottomright))
{
goto out;
}
}
// 3D floor is completely within this light

View file

@ -387,7 +387,7 @@ void GLWall::RenderTranslucentWall()
{
if (gltexture)
{
if (gl_fixedcolormap == CM_DEFAULT && gl_lights && (gl.flags & RFL_BUFFER_STORAGE))
if (gl_fixedcolormap == CM_DEFAULT && gl_lights && gl.lightmethod == LM_DIRECT)
{
SetupLights();
}

View file

@ -53,7 +53,7 @@ void FBloomExtractShader::Bind()
{
if (!mShader)
{
mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/bloomextract.vp", "", 330);
mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/bloomextract.fp", "", 330);
mShader.SetFragDataLocation(0, "FragColor");
mShader.Link("shaders/glsl/bloomextract");
@ -68,7 +68,7 @@ void FBloomCombineShader::Bind()
{
if (!mShader)
{
mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/bloomcombine.vp", "", 330);
mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/bloomcombine.fp", "", 330);
mShader.SetFragDataLocation(0, "FragColor");
mShader.Link("shaders/glsl/bloomcombine");

View file

@ -0,0 +1,68 @@
/*
** gl_lensshader.cpp
** Lens distortion with chromatic aberration shader
**
**---------------------------------------------------------------------------
** Copyright 2016 Magnus Norddahl
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
** covered by the terms of the GNU Lesser General Public License as published
** by the Free Software Foundation; either version 2.1 of the License, or (at
** your option) any later version.
** 5. Full disclosure of the entire project's source code, except for third
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "gl/system/gl_system.h"
#include "files.h"
#include "m_swap.h"
#include "v_video.h"
#include "gl/gl_functions.h"
#include "vectors.h"
#include "gl/system/gl_interface.h"
#include "gl/system/gl_framebuffer.h"
#include "gl/system/gl_cvars.h"
#include "gl/shaders/gl_lensshader.h"
void FLensShader::Bind()
{
if (!mShader)
{
mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/lensdistortion.fp", "", 330);
mShader.SetFragDataLocation(0, "FragColor");
mShader.Link("shaders/glsl/lensdistortion");
mShader.SetAttribLocation(0, "PositionInProjection");
InputTexture.Init(mShader, "InputTexture");
AspectRatio.Init(mShader, "Aspect");
Scale.Init(mShader, "Scale");
LensDistortionCoefficient.Init(mShader, "k");
CubicDistortionValue.Init(mShader, "kcube");
}
mShader.Bind();
}

View file

@ -0,0 +1,21 @@
#ifndef __GL_LENSSHADER_H
#define __GL_LENSSHADER_H
#include "gl_shaderprogram.h"
class FLensShader
{
public:
void Bind();
FBufferedUniform1i InputTexture;
FBufferedUniform1f AspectRatio;
FBufferedUniform1f Scale;
FBufferedUniform4f LensDistortionCoefficient;
FBufferedUniform4f CubicDistortionValue;
private:
FShaderProgram mShader;
};
#endif

View file

@ -53,7 +53,7 @@ void FPresentShader::Bind()
{
if (!mShader)
{
mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/present.vp", "", 330);
mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquadscale.vp", "", 330);
mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/present.fp", "", 330);
mShader.SetFragDataLocation(0, "FragColor");
mShader.Link("shaders/glsl/present");
@ -63,6 +63,7 @@ void FPresentShader::Bind()
Gamma.Init(mShader, "Gamma");
Contrast.Init(mShader, "Contrast");
Brightness.Init(mShader, "Brightness");
Scale.Init(mShader, "UVScale");
}
mShader.Bind();
}

View file

@ -12,6 +12,7 @@ public:
FBufferedUniform1f Gamma;
FBufferedUniform1f Contrast;
FBufferedUniform1f Brightness;
FBufferedUniform2f Scale;
private:
FShaderProgram mShader;

View file

@ -169,6 +169,12 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char *
FShaderProgram::PatchVertShader(vp_comb);
FShaderProgram::PatchFragShader(fp_comb);
}
else if (gl.flags & RFL_NO_CLIP_PLANES)
{
// On ATI's GL3 drivers we have to disable gl_ClipDistance because it's hopelessly broken.
// This will cause some glitches and regressions but is the only way to avoid total display garbage.
vp_comb.Substitute("gl_ClipDistance", "//");
}
hVertProg = glCreateShader(GL_VERTEX_SHADER);
hFragProg = glCreateShader(GL_FRAGMENT_SHADER);

View file

@ -123,6 +123,17 @@ public:
glUniform2fv(mIndex, 1, newvalue);
}
}
void Set(float f1, float f2)
{
if (mBuffer[0] != f1 || mBuffer[1] != f2)
{
mBuffer[0] = f1;
mBuffer[1] = f2;
glUniform2fv(mIndex, 1, mBuffer);
}
}
};
class FBufferedUniform4f

View file

@ -54,7 +54,7 @@ void FTonemapShader::Bind()
auto &shader = mShader[gl_tonemap];
if (!shader)
{
shader.Compile(FShaderProgram::Vertex, "shaders/glsl/tonemap.vp", "", 330);
shader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
shader.Compile(FShaderProgram::Fragment, "shaders/glsl/tonemap.fp", GetDefines(gl_tonemap), 330);
shader.SetFragDataLocation(0, "FragColor");
shader.Link("shaders/glsl/tonemap");

View file

@ -49,5 +49,9 @@ EXTERN_CVAR(Float, gl_bloom_amount)
EXTERN_CVAR(Int, gl_bloom_kernel_size)
EXTERN_CVAR(Int, gl_tonemap)
EXTERN_CVAR(Float, gl_exposure)
EXTERN_CVAR(Bool, gl_lens)
EXTERN_CVAR(Float, gl_lens_k)
EXTERN_CVAR(Float, gl_lens_kcube)
EXTERN_CVAR(Float, gl_lens_chromatic)
#endif // _GL_INTERN_H

View file

@ -64,6 +64,7 @@
#include "gl/utility/gl_clock.h"
#include "gl/utility/gl_templates.h"
#include "gl/gl_functions.h"
#include "gl/renderer/gl_2ddrawer.h"
IMPLEMENT_CLASS(OpenGLFrameBuffer)
EXTERN_CVAR (Float, vid_brightness)
@ -93,6 +94,10 @@ CUSTOM_CVAR(Int, vid_hwgamma, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITC
OpenGLFrameBuffer::OpenGLFrameBuffer(void *hMonitor, int width, int height, int bits, int refreshHz, bool fullscreen) :
Super(hMonitor, width, height, bits, refreshHz, fullscreen)
{
// SetVSync needs to be at the very top to workaround a bug in Nvidia's OpenGL driver.
// If wglSwapIntervalEXT is called after glBindFramebuffer in a frame the setting is not changed!
SetVSync(vid_vsync);
GLRenderer = new FGLRenderer(this);
memcpy (SourcePalette, GPalette.BaseColors, sizeof(PalEntry)*256);
UpdatePalette ();
@ -106,7 +111,6 @@ OpenGLFrameBuffer::OpenGLFrameBuffer(void *hMonitor, int width, int height, int
needsetgamma = true;
swapped = false;
Accel2D = true;
SetVSync(vid_vsync);
}
OpenGLFrameBuffer::~OpenGLFrameBuffer()
@ -160,7 +164,7 @@ void OpenGLFrameBuffer::InitializeState()
//int h = GetHeight();
//glViewport(0, (trueH - h)/2, GetWidth(), GetHeight());
GLRenderer->Initialize();
GLRenderer->Initialize(GetWidth(), GetHeight());
GLRenderer->SetOutputViewport(nullptr);
Begin2D(false);
}
@ -386,7 +390,8 @@ bool OpenGLFrameBuffer::Begin2D(bool)
void OpenGLFrameBuffer::DrawTextureParms(FTexture *img, DrawParms &parms)
{
if (GLRenderer != NULL) GLRenderer->DrawTexture(img, parms);
if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr)
GLRenderer->m2DDrawer->AddTexture(img, parms);
}
//==========================================================================
@ -396,8 +401,8 @@ void OpenGLFrameBuffer::DrawTextureParms(FTexture *img, DrawParms &parms)
//==========================================================================
void OpenGLFrameBuffer::DrawLine(int x1, int y1, int x2, int y2, int palcolor, uint32 color)
{
if (GLRenderer != NULL)
GLRenderer->DrawLine(x1, y1, x2, y2, palcolor, color);
if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr)
GLRenderer->m2DDrawer->AddLine(x1, y1, x2, y2, palcolor, color);
}
//==========================================================================
@ -407,8 +412,8 @@ void OpenGLFrameBuffer::DrawLine(int x1, int y1, int x2, int y2, int palcolor, u
//==========================================================================
void OpenGLFrameBuffer::DrawPixel(int x1, int y1, int palcolor, uint32 color)
{
if (GLRenderer != NULL)
GLRenderer->DrawPixel(x1, y1, palcolor, color);
if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr)
GLRenderer->m2DDrawer->AddPixel(x1, y1, palcolor, color);
}
//==========================================================================
@ -425,8 +430,8 @@ void OpenGLFrameBuffer::Dim(PalEntry)
void OpenGLFrameBuffer::Dim(PalEntry color, float damount, int x1, int y1, int w, int h)
{
if (GLRenderer != NULL)
GLRenderer->Dim(color, damount, x1, y1, w, h);
if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr)
GLRenderer->m2DDrawer->AddDim(color, damount, x1, y1, w, h);
}
//==========================================================================
@ -437,8 +442,8 @@ void OpenGLFrameBuffer::Dim(PalEntry color, float damount, int x1, int y1, int w
void OpenGLFrameBuffer::FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin)
{
if (GLRenderer != NULL)
GLRenderer->FlatFill(left, top, right, bottom, src, local_origin);
if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr)
GLRenderer->m2DDrawer->AddFlatFill(left, top, right, bottom, src, local_origin);
}
//==========================================================================
@ -448,8 +453,8 @@ void OpenGLFrameBuffer::FlatFill (int left, int top, int right, int bottom, FTex
//==========================================================================
void OpenGLFrameBuffer::Clear(int left, int top, int right, int bottom, int palcolor, uint32 color)
{
if (GLRenderer != NULL)
GLRenderer->Clear(left, top, right, bottom, palcolor, color);
if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr)
GLRenderer->m2DDrawer->AddClear(left, top, right, bottom, palcolor, color);
}
//==========================================================================
@ -464,10 +469,9 @@ void OpenGLFrameBuffer::FillSimplePoly(FTexture *texture, FVector2 *points, int
double originx, double originy, double scalex, double scaley,
DAngle rotation, FDynamicColormap *colormap, int lightlevel)
{
if (GLRenderer != NULL)
if (GLRenderer != nullptr && GLRenderer->m2DDrawer != nullptr && npoints >= 3)
{
GLRenderer->FillSimplePoly(texture, points, npoints, originx, originy, scalex, scaley,
rotation, colormap, lightlevel);
GLRenderer->m2DDrawer->AddPoly(texture, points, npoints, originx, originy, scalex, scaley, rotation, colormap, lightlevel);
}
}

View file

@ -7,6 +7,7 @@
#endif
class FHardwareTexture;
class FSimpleVertexBuffer;
extern long gl_frameMS;
extern long gl_frameCount;
@ -94,7 +95,14 @@ private:
class Wiper
{
protected:
FSimpleVertexBuffer *mVertexBuf;
void MakeVBO(OpenGLFrameBuffer *fb);
public:
Wiper();
virtual ~Wiper();
virtual bool Run(int ticks, OpenGLFrameBuffer *fb) = 0;
};

View file

@ -167,6 +167,7 @@ void gl_LoadExtensions()
gl.vendorstring = (char*)glGetString(GL_VENDOR);
gl.lightmethod = LM_SOFTWARE;
gl.buffermethod = BM_CLIENTARRAY;
if ((gl.version >= 3.3f || CheckExtension("GL_ARB_sampler_objects")) && !Args->CheckParm("-nosampler"))
{
@ -177,35 +178,41 @@ void gl_LoadExtensions()
if (gl.version > 3.0f && (gl.version >= 3.3f || CheckExtension("GL_ARB_uniform_buffer_object")))
{
gl.lightmethod = LM_DEFERRED;
// Only Apple requires the core profile for GL 3.x+.
// #ifdef __APPLE__
// gl.buffermethod = BM_DEFERRED;
// #endif
}
if (CheckExtension("GL_ARB_texture_compression")) gl.flags |= RFL_TEXTURE_COMPRESSION;
if (CheckExtension("GL_EXT_texture_compression_s3tc")) gl.flags |= RFL_TEXTURE_COMPRESSION_S3TC;
if (Args->CheckParm("-noshader") || gl.glslversion < 1.2f)
if (Args->CheckParm("-noshader")/* || gl.glslversion < 1.2f*/)
{
gl.version = 2.11f;
gl.glslversion = 0;
gl.lightmethod = LM_SOFTWARE;
gl.flags |= RFL_NO_CLIP_PLANES;
}
else if (gl.version < 3.0f)
{
if (CheckExtension("GL_NV_GPU_shader4") || CheckExtension("GL_EXT_GPU_shader4")) gl.glslversion = 1.21f; // for pre-3.0 drivers that support capable hardware. Needed for Apple.
else gl.glslversion = 0;
//if (CheckExtension("GL_NV_GPU_shader4") || CheckExtension("GL_EXT_GPU_shader4")) gl.glslversion = 1.21f; // for pre-3.0 drivers that support capable hardware. Needed for Apple.
//else gl.glslversion = 0;
if (!CheckExtension("GL_EXT_packed_float")) gl.flags |= RFL_NO_RGBA16F;
if (!CheckExtension("GL_EXT_packed_depth_stencil")) gl.flags |= RFL_NO_DEPTHSTENCIL;
gl.flags |= RFL_NO_CLIP_PLANES;
}
else if (gl.version < 4.f)
{
#ifdef _WIN32
if (strstr(gl.vendorstring, "ATI Tech"))
{
gl.version = 2.11f;
gl.glslversion = 1.21f;
gl.lightmethod = LM_SOFTWARE; // do not use uniform buffers with the fallback shader, it may cause problems.
gl.flags |= RFL_NO_CLIP_PLANES; // gl_ClipDistance is horribly broken on ATI GL3 drivers for Windows.
}
#endif
}
else
else if (gl.version < 4.5f)
{
// don't use GL 4.x features when running in GL 3 emulation mode.
if (CheckExtension("GL_ARB_buffer_storage"))
@ -222,12 +229,20 @@ void gl_LoadExtensions()
}
gl.flags |= RFL_BUFFER_STORAGE;
gl.lightmethod = LM_DIRECT;
gl.buffermethod = BM_PERSISTENT;
}
else
{
gl.version = 3.3f;
}
}
else
{
// Assume that everything works without problems on GL 4.5 drivers where these things are core features.
gl.flags |= RFL_SHADER_STORAGE_BUFFER | RFL_BUFFER_STORAGE;
gl.lightmethod = LM_DIRECT;
gl.buffermethod = BM_PERSISTENT;
}
const char *lm = Args->CheckValue("-lightmethod");
if (lm != NULL)
@ -236,6 +251,13 @@ void gl_LoadExtensions()
if (!stricmp(lm, "textured")) gl.lightmethod = LM_SOFTWARE;
}
lm = Args->CheckValue("-buffermethod");
if (lm != NULL)
{
//if (!stricmp(lm, "deferred") && gl.buffermethod == BM_PERSISTENT) gl.buffermethod = BM_DEFERRED;
if (!stricmp(lm, "clientarray")) gl.buffermethod = BM_CLIENTARRAY;
}
int v;
if (gl.lightmethod != LM_SOFTWARE && !(gl.flags & RFL_SHADER_STORAGE_BUFFER))

View file

@ -22,7 +22,8 @@ enum RenderFlags
RFL_SAMPLER_OBJECTS = 16,
RFL_NO_RGBA16F = 32,
RFL_NO_DEPTHSTENCIL = 64
RFL_NO_DEPTHSTENCIL = 64,
RFL_NO_CLIP_PLANES = 128
};
enum TexMode
@ -44,6 +45,14 @@ enum ELightMethod
LM_DIRECT = 2, // calculate lights on the fly along with the render data
};
enum EBufferMethod
{
BM_CLIENTARRAY = 0, // use a client array instead of a hardware buffer
BM_DEFERRED = 1, // use a temporarily mapped buffer (only necessary on GL 3.x core profile, i.e. Apple)
BM_PERSISTENT = 2 // use a persistently mapped buffer
};
struct RenderContext
{
unsigned int flags;
@ -51,6 +60,7 @@ struct RenderContext
unsigned int maxuniformblock;
unsigned int uniformblockalignment;
int lightmethod;
int buffermethod;
float version;
float glslversion;
int max_texturesize;

View file

@ -61,6 +61,7 @@
#include "gl/textures/gl_samplers.h"
#include "gl/utility/gl_templates.h"
#include "gl/data/gl_vertexbuffer.h"
#include "gl/renderer/gl_2ddrawer.h"
#ifndef _WIN32
struct POINT {
@ -97,6 +98,7 @@ class OpenGLFrameBuffer::Wiper_Melt : public OpenGLFrameBuffer::Wiper
{
public:
Wiper_Melt();
int MakeVBO(int ticks, OpenGLFrameBuffer *fb, bool &done);
bool Run(int ticks, OpenGLFrameBuffer *fb);
private:
@ -158,7 +160,7 @@ bool OpenGLFrameBuffer::WipeStartScreen(int type)
if (FGLRenderBuffers::IsEnabled())
{
GLRenderer->mBuffers->BindHudFB();
GLRenderer->mBuffers->BindCurrentFB();
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Width, Height);
}
else
@ -186,6 +188,7 @@ bool OpenGLFrameBuffer::WipeStartScreen(int type)
void OpenGLFrameBuffer::WipeEndScreen()
{
GLRenderer->m2DDrawer->Flush();
wipeendscreen = new FHardwareTexture(Width, Height, true);
wipeendscreen->CreateTexture(NULL, Width, Height, 0, false, 0);
GLRenderer->mSamplerManager->Bind(0, CLAMP_NOFILTER, -1);
@ -193,7 +196,7 @@ void OpenGLFrameBuffer::WipeEndScreen()
wipeendscreen->Bind(0, false, false);
if (FGLRenderBuffers::IsEnabled())
GLRenderer->mBuffers->BindHudFB();
GLRenderer->mBuffers->BindCurrentFB();
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Width, Height);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@ -217,29 +220,28 @@ void OpenGLFrameBuffer::WipeEndScreen()
bool OpenGLFrameBuffer::WipeDo(int ticks)
{
bool done = true;
// Sanity checks.
if (wipestartscreen == NULL || wipeendscreen == NULL)
if (wipestartscreen != nullptr && wipeendscreen != nullptr)
{
return true;
Lock(true);
gl_RenderState.EnableTexture(true);
gl_RenderState.EnableFog(false);
glDisable(GL_DEPTH_TEST);
glDepthMask(false);
if (FGLRenderBuffers::IsEnabled())
{
GLRenderer->mBuffers->BindCurrentFB();
const auto &bounds = GLRenderer->mScreenViewport;
glViewport(bounds.left, bounds.top, bounds.width, bounds.height);
}
done = ScreenWipe->Run(ticks, this);
glDepthMask(true);
}
Lock(true);
gl_RenderState.EnableTexture(true);
gl_RenderState.EnableFog(false);
glDisable(GL_DEPTH_TEST);
glDepthMask(false);
if (FGLRenderBuffers::IsEnabled())
{
GLRenderer->mBuffers->BindHudFB();
const auto &bounds = GLRenderer->mScreenViewport;
glViewport(bounds.left, bounds.top, bounds.width, bounds.height);
}
bool done = ScreenWipe->Run(ticks, this);
glDepthMask(true);
//DrawLetterbox();
gl_RenderState.SetVertexBuffer(GLRenderer->mVBO);
return done;
}
@ -276,9 +278,32 @@ void OpenGLFrameBuffer::WipeCleanup()
// OpenGLFrameBuffer :: Wiper Constructor
//
//==========================================================================
OpenGLFrameBuffer::Wiper::Wiper()
{
mVertexBuf = new FSimpleVertexBuffer;
}
OpenGLFrameBuffer::Wiper::~Wiper()
{
delete mVertexBuf;
}
void OpenGLFrameBuffer::Wiper::MakeVBO(OpenGLFrameBuffer *fb)
{
FSimpleVertex make[4];
FSimpleVertex *ptr = make;
float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth());
float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight());
ptr->Set(0, 0, 0, 0, vb);
ptr++;
ptr->Set(0, fb->Height, 0, 0, 0);
ptr++;
ptr->Set(fb->Width, 0, 0, ur, vb);
ptr++;
ptr->Set(fb->Width, fb->Height, 0, ur, 0);
mVertexBuf->set(make, 4);
}
// WIPE: CROSSFADE ---------------------------------------------------------
@ -306,32 +331,20 @@ bool OpenGLFrameBuffer::Wiper_Crossfade::Run(int ticks, OpenGLFrameBuffer *fb)
{
Clock += ticks;
float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth());
float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight());
MakeVBO(fb);
gl_RenderState.SetTextureMode(TM_OPAQUE);
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
gl_RenderState.ResetColor();
gl_RenderState.Apply();
fb->wipestartscreen->Bind(0, 0, false);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
FFlatVertex *ptr;
unsigned int offset, count;
ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(0, 0, 0, 0, vb);
ptr++;
ptr->Set(0, fb->Height, 0, 0, 0);
ptr++;
ptr->Set(fb->Width, 0, 0, ur, vb);
ptr++;
ptr->Set(fb->Width, fb->Height, 0, ur, 0);
ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP, &offset, &count);
fb->wipeendscreen->Bind(0, 0, false);
gl_RenderState.SetColorAlpha(0xffffff, clamp(Clock/32.f, 0.f, 1.f));
float a = clamp(Clock / 32.f, 0.f, 1.f);
gl_RenderState.SetColorAlpha(0xffffff, a);
gl_RenderState.Apply();
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, offset, count);
fb->wipeendscreen->Bind(0, 0, false);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.5f);
gl_RenderState.SetTextureMode(TM_MODULATE);
@ -366,18 +379,15 @@ OpenGLFrameBuffer::Wiper_Melt::Wiper_Melt()
//
//==========================================================================
bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb)
int OpenGLFrameBuffer::Wiper_Melt::MakeVBO(int ticks, OpenGLFrameBuffer *fb, bool &done)
{
FSimpleVertex *make = new FSimpleVertex[321*4];
FSimpleVertex *ptr = make;
int dy;
float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth());
float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight());
// Draw the new screen on the bottom.
gl_RenderState.SetTextureMode(TM_OPAQUE);
gl_RenderState.ResetColor();
gl_RenderState.Apply();
fb->wipeendscreen->Bind(0, 0, false);
FFlatVertex *ptr;
ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(0, 0, 0, 0, vb);
ptr++;
ptr->Set(0, fb->Height, 0, 0, 0);
@ -386,31 +396,26 @@ bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb)
ptr++;
ptr->Set(fb->Width, fb->Height, 0, ur, 0);
ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
int i, dy;
bool done = false;
fb->wipestartscreen->Bind(0, 0, false);
// Copy the old screen in vertical strips on top of the new one.
while (ticks--)
{
done = true;
for (i = 0; i < WIDTH; i++)
for (int i = 0; i < WIDTH; i++)
{
if (y[i] < 0)
{
y[i]++;
done = false;
}
}
else if (y[i] < HEIGHT)
{
dy = (y[i] < 16) ? y[i]+1 : 8;
dy = (y[i] < 16) ? y[i] + 1 : 8;
y[i] = MIN(y[i] + dy, HEIGHT);
done = false;
}
if (ticks == 0)
{
{
// Only draw for the final tick.
// No need for optimization. Wipes won't ever be drawn with anything else.
RECT rect;
@ -429,7 +434,6 @@ bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb)
rect.bottom = fb->Height - rect.bottom;
rect.top = fb->Height - rect.top;
ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(rect.left, rect.bottom, 0, rect.left / tw, rect.top / th);
ptr++;
ptr->Set(rect.left, rect.top, 0, rect.left / tw, rect.bottom / th);
@ -438,12 +442,34 @@ bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb)
ptr++;
ptr->Set(rect.right, rect.top, 0, rect.right / tw, rect.bottom / th);
ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP);
}
}
}
}
int numverts = int(ptr - make);
mVertexBuf->set(make, numverts);
delete[] make;
return numverts;
}
bool OpenGLFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLFrameBuffer *fb)
{
bool done = false;
int maxvert = MakeVBO(ticks, fb, done);
// Draw the new screen on the bottom.
gl_RenderState.SetTextureMode(TM_OPAQUE);
gl_RenderState.ResetColor();
gl_RenderState.Apply();
fb->wipeendscreen->Bind(0, 0, false);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
fb->wipestartscreen->Bind(0, 0, false);
gl_RenderState.SetTextureMode(TM_MODULATE);
for (int i = 4; i < maxvert; i += 4)
{
glDrawArrays(GL_TRIANGLE_STRIP, i, 4);
}
return done;
}
@ -486,6 +512,8 @@ bool OpenGLFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLFrameBuffer *fb)
{
bool done;
MakeVBO(fb);
BurnTime += ticks;
ticks *= 2;
@ -524,18 +552,7 @@ bool OpenGLFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLFrameBuffer *fb)
gl_RenderState.ResetColor();
gl_RenderState.Apply();
fb->wipestartscreen->Bind(0, 0, false);
FFlatVertex *ptr;
unsigned int offset, count;
ptr = GLRenderer->mVBO->GetBuffer();
ptr->Set(0, 0, 0, 0, vb);
ptr++;
ptr->Set(0, fb->Height, 0, 0, 0);
ptr++;
ptr->Set(fb->Width, 0, 0, ur, vb);
ptr++;
ptr->Set(fb->Width, fb->Height, 0, ur, 0);
ptr++;
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP, &offset, &count);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
gl_RenderState.SetTextureMode(TM_MODULATE);
gl_RenderState.SetEffect(EFF_BURN);
@ -547,7 +564,7 @@ bool OpenGLFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLFrameBuffer *fb)
BurnTexture->CreateTexture(rgb_buffer, WIDTH, HEIGHT, 1, true, 0);
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, offset, count);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
gl_RenderState.SetEffect(EFF_NONE);
// The fire may not always stabilize, so the wipe is forced to end

View file

@ -654,6 +654,7 @@ xx(DecoCallLineSpecial)
xx(DecoNameToClass)
xx(DecoFindMultiNameState)
xx(DecoFindSingleNameState)
xx(DecoHandleRuntimeState)
xx(Damage)
// basic type names

View file

@ -514,6 +514,17 @@ void P_Recalculate3DFloors(sector_t * sector)
clipped_bottom = pick_bottom;
}
}
else if (pick_bottom > height) // do not allow inverted planes
{
F3DFloor * dyn = new F3DFloor;
*dyn = *pick;
pick->flags |= FF_CLIPPED;
pick->flags &= ~FF_EXISTS;
dyn->flags |= FF_DYNAMIC;
dyn->bottom.copyPlane(&pick->top);
ffloors.Push(pick);
ffloors.Push(dyn);
}
else
{
clipped = pick;

View file

@ -310,7 +310,7 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t
break;
case DCeiling::ceilLowerToHighestFloor:
targheight = sec->FindHighestFloorSurrounding (&spot);
targheight = sec->FindHighestFloorSurrounding (&spot) + height;
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
@ -360,13 +360,13 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t
break;
case DCeiling::ceilLowerToFloor:
targheight = sec->FindHighestFloorPoint (&spot);
targheight = sec->FindHighestFloorPoint (&spot) + height;
ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = -1;
break;
case DCeiling::ceilRaiseToFloor: // [RH] What's this for?
targheight = sec->FindHighestFloorPoint (&spot);
targheight = sec->FindHighestFloorPoint (&spot) + height;
ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight);
ceiling->m_Direction = 1;
break;
@ -553,21 +553,31 @@ void P_ActivateInStasisCeiling (int tag)
//
//============================================================================
bool EV_CeilingCrushStop (int tag)
bool EV_CeilingCrushStop (int tag, bool remove)
{
bool rtn = false;
DCeiling *scan;
TThinkerIterator<DCeiling> iterator;
while ( (scan = iterator.Next ()) )
scan = iterator.Next();
while (scan != nullptr)
{
DCeiling *next = iterator.Next();
if (scan->m_Tag == tag && scan->m_Direction != 0)
{
SN_StopSequence (scan->m_Sector, CHAN_CEILING);
scan->m_OldDirection = scan->m_Direction;
scan->m_Direction = 0; // in-stasis;
if (!remove)
{
SN_StopSequence(scan->m_Sector, CHAN_CEILING);
scan->m_OldDirection = scan->m_Direction;
scan->m_Direction = 0; // in-stasis;
}
else
{
scan->Destroy();
}
rtn = true;
}
scan = next;
}
return rtn;

View file

@ -350,16 +350,14 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line,
break;
case DFloor::floorRaiseAndCrushDoom:
height = 8;
case DFloor::floorRaiseToLowestCeiling:
floor->m_Direction = 1;
newheight = sec->FindLowestCeilingSurrounding(&spot);
if (floortype == DFloor::floorRaiseAndCrushDoom)
newheight -= 8;
newheight = sec->FindLowestCeilingSurrounding(&spot) - height;
ceilingheight = sec->FindLowestCeilingPoint(&spot2);
floor->m_FloorDestDist = sec->floorplane.PointToDist(spot, newheight);
if (sec->floorplane.ZatPointDist(spot2, floor->m_FloorDestDist) > ceilingheight)
floor->m_FloorDestDist = sec->floorplane.PointToDist(spot2,
floortype == DFloor::floorRaiseAndCrushDoom ? ceilingheight - 8 : ceilingheight);
floor->m_FloorDestDist = sec->floorplane.PointToDist(spot2, floortype == ceilingheight - height);
break;
case DFloor::floorRaiseToHighest:
@ -388,7 +386,7 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line,
case DFloor::floorRaiseToCeiling:
floor->m_Direction = 1;
newheight = sec->FindLowestCeilingPoint(&spot);
newheight = sec->FindLowestCeilingPoint(&spot) - height;
floor->m_FloorDestDist = sec->floorplane.PointToDist(spot, newheight);
break;
@ -407,7 +405,7 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line,
case DFloor::floorLowerToCeiling:
// [RH] Essentially instantly raises the floor to the ceiling
floor->m_Direction = -1;
newheight = sec->FindLowestCeilingPoint(&spot);
newheight = sec->FindLowestCeilingPoint(&spot) - height;
floor->m_FloorDestDist = sec->floorplane.PointToDist(spot, newheight);
break;

View file

@ -263,7 +263,13 @@ FUNC(LS_Door_Raise)
FUNC(LS_Door_LockedRaise)
// Door_LockedRaise (tag, speed, delay, lock, lighttag)
{
#if 0
// In Hexen this originally created a thinker running for nearly 4 years.
// Let's not do this unless it becomes necessary because this can hang tagwait.
return EV_DoDoor (arg2 || (level.flags2 & LEVEL2_HEXENHACK) ? DDoor::doorRaise : DDoor::doorOpen, ln, it,
#else
return EV_DoDoor (arg2 ? DDoor::doorRaise : DDoor::doorOpen, ln, it,
#endif
arg0, SPEED(arg1), TICS(arg2), arg3, arg4);
}
@ -423,9 +429,9 @@ FUNC(LS_Floor_RaiseInstant)
}
FUNC(LS_Floor_ToCeilingInstant)
// Floor_ToCeilingInstant (tag, change, crush)
// Floor_ToCeilingInstant (tag, change, crush, gap)
{
return EV_DoFloor (DFloor::floorLowerToCeiling, ln, arg0, 0, 0, CRUSH(arg2), CHANGE(arg1), true);
return EV_DoFloor (DFloor::floorLowerToCeiling, ln, arg0, 0, arg3, CRUSH(arg2), CHANGE(arg1), true);
}
FUNC(LS_Floor_MoveToValueTimes8)
@ -451,7 +457,7 @@ FUNC(LS_Floor_RaiseToLowestCeiling)
FUNC(LS_Floor_LowerToLowestCeiling)
// Floor_LowerToLowestCeiling (tag, speed, change)
{
return EV_DoFloor (DFloor::floorLowerToLowestCeiling, ln, arg0, SPEED(arg1), 0, -1, CHANGE(arg2), true);
return EV_DoFloor (DFloor::floorLowerToLowestCeiling, ln, arg0, SPEED(arg1), arg4, -1, CHANGE(arg2), true);
}
FUNC(LS_Floor_RaiseByTexture)
@ -467,9 +473,9 @@ FUNC(LS_Floor_LowerByTexture)
}
FUNC(LS_Floor_RaiseToCeiling)
// Floor_RaiseToCeiling (tag, speed, change, crush)
// Floor_RaiseToCeiling (tag, speed, change, crush, gap)
{
return EV_DoFloor (DFloor::floorRaiseToCeiling, ln, arg0, SPEED(arg1), 0, CRUSH(arg3), CHANGE(arg2), true);
return EV_DoFloor (DFloor::floorRaiseToCeiling, ln, arg0, SPEED(arg1), arg4, CRUSH(arg3), CHANGE(arg2), true);
}
FUNC(LS_Floor_RaiseByValueTxTy)
@ -683,9 +689,22 @@ FUNC(LS_Ceiling_LowerAndCrushDist)
}
FUNC(LS_Ceiling_CrushStop)
// Ceiling_CrushStop (tag)
// Ceiling_CrushStop (tag, remove)
{
return EV_CeilingCrushStop (arg0);
bool remove;
switch (arg3)
{
case 1:
remove = false;
break;
case 2:
remove = true;
break;
default:
remove = gameinfo.gametype == GAME_Hexen;
break;
}
return EV_CeilingCrushStop (arg0, remove);
}
FUNC(LS_Ceiling_CrushRaiseAndStay)
@ -709,9 +728,9 @@ FUNC(LS_Ceiling_MoveToValue)
}
FUNC(LS_Ceiling_LowerToHighestFloor)
// Ceiling_LowerToHighestFloor (tag, speed, change, crush)
// Ceiling_LowerToHighestFloor (tag, speed, change, crush, gap)
{
return EV_DoCeiling (DCeiling::ceilLowerToHighestFloor, ln, arg0, SPEED(arg1), 0, 0, CRUSH(arg3), 0, CHANGE(arg2));
return EV_DoCeiling (DCeiling::ceilLowerToHighestFloor, ln, arg0, SPEED(arg1), 0, arg4, CRUSH(arg3), 0, CHANGE(arg2));
}
FUNC(LS_Ceiling_LowerInstant)
@ -811,15 +830,15 @@ FUNC(LS_Ceiling_ToHighestInstant)
}
FUNC(LS_Ceiling_ToFloorInstant)
// Ceiling_ToFloorInstant (tag, change, crush)
// Ceiling_ToFloorInstant (tag, change, crush, gap)
{
return EV_DoCeiling (DCeiling::ceilRaiseToFloor, ln, arg0, 2, 0, 0, CRUSH(arg2), 0, CHANGE(arg1));
return EV_DoCeiling (DCeiling::ceilRaiseToFloor, ln, arg0, 2, 0, arg3, CRUSH(arg2), 0, CHANGE(arg1));
}
FUNC(LS_Ceiling_LowerToFloor)
// Ceiling_LowerToFloor (tag, speed, change, crush)
// Ceiling_LowerToFloor (tag, speed, change, crush, gap)
{
return EV_DoCeiling (DCeiling::ceilLowerToFloor, ln, arg0, SPEED(arg1), 0, 0, CRUSH(arg3), 0, CHANGE(arg4));
return EV_DoCeiling (DCeiling::ceilLowerToFloor, ln, arg0, SPEED(arg1), 0, arg4, CRUSH(arg3), 0, CHANGE(arg4));
}
FUNC(LS_Ceiling_LowerByTexture)
@ -887,9 +906,22 @@ FUNC(LS_Plat_PerpetualRaiseLip)
}
FUNC(LS_Plat_Stop)
// Plat_Stop (tag)
// Plat_Stop (tag, remove?)
{
EV_StopPlat (arg0);
bool remove;
switch (arg3)
{
case 1:
remove = false;
break;
case 2:
remove = true;
break;
default:
remove = gameinfo.gametype == GAME_Hexen;
break;
}
EV_StopPlat(arg0, remove);
return true;
}

View file

@ -435,7 +435,8 @@ bool P_TeleportMove(AActor* thing, const DVector3 &pos, bool telefrag, bool modi
// If this teleport was caused by a move, P_TryMove() will handle the
// sector transition messages better than we can here.
if (!(thing->flags6 & MF6_INTRYMOVE))
// This needs to be compatibility optioned because some older maps exploited this missing feature.
if (!(thing->flags6 & MF6_INTRYMOVE) && !(i_compatflags2 & COMPATF2_TELEPORT))
{
thing->CheckSectorTransition(oldsec);
}
@ -1912,7 +1913,7 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, DVector2 *
{
if (line->special && !(mobj->flags6 & MF6_NOTRIGGER))
{
if (posforwindowcheck && !(ib_compatflags & BCOMPATF_NOWINDOWCHECK) && line->backsector != NULL)
if (posforwindowcheck && !(i_compatflags2 & COMPATF2_PUSHWINDOW) && line->backsector != NULL)
{ // Make sure this line actually blocks us and is not a window
// or similar construct we are standing inside of.
DVector3 pos = mobj->PosRelative(line);
@ -4439,6 +4440,9 @@ AActor *P_LinePickActor(AActor *t1, DAngle angle, double distance, DAngle pitch,
TData.Caller = t1;
TData.hitGhosts = true;
TData.MThruSpecies = false;
TData.ThruActors = false;
TData.ThruSpecies = false;
if (Trace(t1->PosAtZ(shootz), t1->Sector, direction, distance,
actorMask, wallMask, t1, trace, TRACE_NoSky | TRACE_PortalRestrict, CheckForActor, &TData))

View file

@ -6405,6 +6405,7 @@ void AActor::Revive()
flags5 = info->flags5;
flags6 = info->flags6;
flags7 = info->flags7;
if (SpawnFlags & MTF_FRIENDLY) flags |= MF_FRIENDLY;
DamageType = info->DamageType;
health = SpawnHealth();
target = NULL;

View file

@ -430,15 +430,21 @@ void DPlat::Stop ()
m_Status = in_stasis;
}
void EV_StopPlat (int tag)
void EV_StopPlat (int tag, bool remove)
{
DPlat *scan;
TThinkerIterator<DPlat> iterator;
while ( (scan = iterator.Next ()) )
scan = iterator.Next();
while (scan != nullptr)
{
DPlat *next = iterator.Next();
if (scan->m_Status != DPlat::in_stasis && scan->m_Tag == tag)
scan->Stop ();
{
if (!remove) scan->Stop();
else scan->Destroy();
}
scan = next;
}
}

View file

@ -1960,7 +1960,7 @@ void P_SetLineID (int i, line_t *ld)
break;
case Plane_Align:
setid = ld->args[2];
if (!(ib_compatflags & BCOMPATF_NOSLOPEID)) setid = ld->args[2];
break;
case Static_Init:

View file

@ -213,13 +213,13 @@ private:
friend bool EV_DoPlat (int tag, line_t *line, EPlatType type,
double height, double speed, int delay, int lip, int change);
friend void EV_StopPlat (int tag);
friend void EV_StopPlat (int tag, bool remove);
friend void P_ActivateInStasis (int tag);
};
bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type,
double height, double speed, int delay, int lip, int change);
void EV_StopPlat (int tag);
void EV_StopPlat (int tag, bool remove);
void P_ActivateInStasis (int tag);
//
@ -435,14 +435,14 @@ private:
DCeiling ();
friend bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int tag, double speed, double speed2, double height, int crush, int silent, int change, DCeiling::ECrushMode hexencrush);
friend bool EV_CeilingCrushStop (int tag);
friend bool EV_CeilingCrushStop (int tag, bool remove);
friend void P_ActivateInStasisCeiling (int tag);
};
bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int tag, double speed, double speed2, double height, int crush, int silent, int change, DCeiling::ECrushMode hexencrush);
bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line, int tag, double speed, double speed2, double height, int crush, int silent, int change, DCeiling::ECrushMode hexencrush = DCeiling::ECrushMode::crushDoom);
bool EV_CeilingCrushStop (int tag);
bool EV_CeilingCrushStop (int tag, bool remove);
void P_ActivateInStasisCeiling (int tag);

View file

@ -1327,6 +1327,17 @@ void FPolyObj::RecalcActorFloorCeil(FBoundingBox bounds) const
while ((actor = it.Next()) != NULL)
{
// skip everything outside the bounding box.
if (actor->X() + actor->radius <= bounds.Left() ||
actor->X() - actor->radius >= bounds.Right() ||
actor->Y() + actor->radius <= bounds.Bottom() ||
actor->Y() - actor->radius >= bounds.Top())
{
continue;
}
// Todo: Be a little more thorough with what gets altered here
// because this can dislocate a lot of items that were spawned on
// the lower side of a sector boundary.
P_FindFloorCeiling(actor);
}
}

View file

@ -292,7 +292,8 @@ static void SetRotation(FLinePortal *port)
else
{
// Linked portals have no angular difference.
port->mSinRot = port->mCosRot = 0.;
port->mSinRot = 0.;
port->mCosRot = 1.;
port->mAngleDiff = 0.;
}
}

View file

@ -270,23 +270,28 @@ static void FinishThingdef()
for (i = 0; i < StateTempCalls.Size(); ++i)
{
FStateTempCall *tcall = StateTempCalls[i];
VMFunction *func;
VMFunction *func = nullptr;
assert(tcall->Code != NULL);
// Can we call this function directly without wrapping it in an
// anonymous function? e.g. Are we passing any parameters to it?
func = tcall->Code->GetDirectFunction();
if (func == NULL)
{
FCompileContext ctx(tcall->ActorClass);
tcall->Code = tcall->Code->Resolve(ctx);
// We don't know the return type in advance for anonymous functions.
FCompileContext ctx(tcall->ActorClass, nullptr);
tcall->Code = tcall->Code->Resolve(ctx);
tcall->Proto = ctx.ReturnProto;
// Make sure resolving it didn't obliterate it.
if (tcall->Code != NULL)
// Make sure resolving it didn't obliterate it.
if (tcall->Code != nullptr)
{
// Can we call this function directly without wrapping it in an
// anonymous function? e.g. Are we passing any parameters to it?
func = tcall->Code->GetDirectFunction();
if (func == nullptr)
{
VMFunctionBuilder buildit;
assert(tcall->Proto != nullptr);
// Allocate registers used to pass parameters in.
// self, stateowner, state (all are pointers)
buildit.Registers[REGT_POINTER].Get(3);
@ -300,15 +305,7 @@ static void FinishThingdef()
// Generate prototype for this anonymous function
TArray<PType *> args(3);
SetImplicitArgs(&args, NULL, tcall->ActorClass, VARF_Method | VARF_Action);
if (tcall->Proto != NULL)
{
sfunc->Proto = NewPrototype(tcall->Proto->ReturnTypes, args);
}
else
{
TArray<PType *> norets(0);
sfunc->Proto = NewPrototype(norets, args);
}
sfunc->Proto = NewPrototype(tcall->Proto->ReturnTypes, args);
func = sfunc;
@ -321,11 +318,9 @@ static void FinishThingdef()
codesize += sfunc->CodeSize;
}
}
}
if (tcall->Code != NULL)
{
delete tcall->Code;
tcall->Code = NULL;
tcall->Code = nullptr;
for (int k = 0; k < tcall->NumStates; ++k)
{
tcall->ActorClass->OwnedStates[tcall->FirstState + k].SetAction(func);
@ -361,16 +356,20 @@ static void FinishThingdef()
if (sfunc == NULL)
{
FCompileContext ctx(ti);
dmg->Resolve(ctx);
VMFunctionBuilder buildit;
buildit.Registers[REGT_POINTER].Get(1); // The self pointer
dmg->Emit(&buildit);
sfunc = buildit.MakeFunction();
sfunc->NumArgs = 1;
sfunc->Proto = NULL; ///FIXME: Need a proper prototype here
// Save this function in case this damage value was reused
// (which happens quite easily with inheritance).
dmg->SetFunction(sfunc);
dmg = static_cast<FxDamageValue *>(dmg->Resolve(ctx));
if (dmg != nullptr)
{
VMFunctionBuilder buildit;
buildit.Registers[REGT_POINTER].Get(1); // The self pointer
dmg->Emit(&buildit);
sfunc = buildit.MakeFunction();
sfunc->NumArgs = 1;
sfunc->Proto = NULL; ///FIXME: Need a proper prototype here
// Save this function in case this damage value was reused
// (which happens quite easily with inheritance).
dmg->SetFunction(sfunc);
}
}
def->Damage = sfunc;

View file

@ -190,10 +190,9 @@ AFuncDesc *FindFunction(const char * string);
void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &bag);
void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params,
PFunction *afd, FString statestring, FStateDefinitions *statedef);
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, PPrototype *&proto, bool &endswithret);
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &endswithret);
class FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag);
FName CheckCastKludges(FName in);
void AddImplicitReturn(class FxSequence *code, const PPrototype *proto, FScanner &sc);
void SetImplicitArgs(TArray<PType *> *args, TArray<DWORD> *argflags, PClassActor *cls, DWORD funcflags);
PFunction *FindGlobalActionFunction(const char *name);
@ -356,6 +355,7 @@ int MatchString (const char *in, const char **strings);
#define ACTION_RETURN_STATE(v) do { FState *state = v; if (numret > 0) { assert(ret != NULL); ret->SetPointer(state, ATAG_STATE); return 1; } return 0; } while(0)
#define ACTION_RETURN_FLOAT(v) do { double u = v; if (numret > 0) { assert(ret != nullptr); ret->SetFloat(u); return 1; } return 0; } while(0)
#define ACTION_RETURN_INT(v) do { int u = v; if (numret > 0) { assert(ret != NULL); ret->SetInt(u); return 1; } return 0; } while(0)
#define ACTION_RETURN_BOOL(v) ACTION_RETURN_INT(v)

View file

@ -631,38 +631,38 @@ void InitThingdef()
// Define some member variables we feel like exposing to the user
PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols;
PType *array5 = NewArray(TypeSInt32, 5);
symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor,Alpha)));
symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Yaw)));
symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor,args)));
symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native, myoffsetof(AActor,ceilingz)));
symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native, myoffsetof(AActor,floorz)));
symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native, myoffsetof(AActor,health)));
symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor,Mass)));
symt.AddSymbol(new PField(NAME_Pitch, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Pitch)));
symt.AddSymbol(new PField(NAME_Roll, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Roll)));
symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor,special)));
symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native, myoffsetof(AActor,tid)));
symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native, myoffsetof(AActor,TIDtoHate)));
symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native, myoffsetof(AActor,waterlevel)));
symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.X))); // must remain read-only!
symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.Y))); // must remain read-only!
symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.Z))); // must remain read-only!
symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native, myoffsetof(AActor,Vel.X)));
symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Y)));
symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Z)));
symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.X)));
symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Y)));
symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Z)));
symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X)));
symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y)));
symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor,Score)));
symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor,accuracy)));
symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor,stamina)));
symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native, myoffsetof(AActor,Height)));
symt.AddSymbol(new PField(NAME_Radius, TypeFloat64, VARF_Native, myoffsetof(AActor,radius)));
symt.AddSymbol(new PField(NAME_ReactionTime,TypeSInt32, VARF_Native, myoffsetof(AActor,reactiontime)));
symt.AddSymbol(new PField(NAME_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor,meleerange)));
symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor,Speed)));
symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native, myoffsetof(AActor,threshold)));
symt.AddSymbol(new PField(NAME_DefThreshold,TypeSInt32, VARF_Native, myoffsetof(AActor,DefThreshold)));
symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor, Alpha)));
symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Yaw)));
symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor, args)));
symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, ceilingz)));
symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, floorz)));
symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, health)));
symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor, Mass)));
symt.AddSymbol(new PField(NAME_Pitch, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Pitch)));
symt.AddSymbol(new PField(NAME_Roll, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Roll)));
symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor, special)));
symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, tid)));
symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, TIDtoHate)));
symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, waterlevel)));
symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.X))); // must remain read-only!
symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Y))); // must remain read-only!
symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Z))); // must remain read-only!
symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X)));
symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y)));
symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z)));
symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X)));
symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y)));
symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z)));
symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X)));
symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y)));
symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor, Score)));
symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor, accuracy)));
symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor, stamina)));
symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Height)));
symt.AddSymbol(new PField(NAME_Radius, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, radius)));
symt.AddSymbol(new PField(NAME_ReactionTime, TypeSInt32, VARF_Native, myoffsetof(AActor, reactiontime)));
symt.AddSymbol(new PField(NAME_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor, meleerange)));
symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor, Speed)));
symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, threshold)));
symt.AddSymbol(new PField(NAME_DefThreshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DefThreshold)));
}

View file

@ -63,6 +63,7 @@ static FxExpression *ParseClamp(FScanner &sc, PClassActor *cls);
//
// ParseExpression
// [GRB] Parses an expression and stores it into Expression array
// It's worth mentioning that this is using C++ operator precedence
//
static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls);
@ -95,18 +96,83 @@ FxExpression *ParseExpression (FScanner &sc, PClassActor *cls, bool mustresolve)
static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls)
{
FxExpression *condition = ParseExpressionL (sc, cls);
FxExpression *base = ParseExpressionL (sc, cls);
if (sc.CheckToken('?'))
{
FxExpression *truex = ParseExpressionM (sc, cls);
sc.MustGetToken(':');
FxExpression *falsex = ParseExpressionM (sc, cls);
return new FxConditional(condition, truex, falsex);
return new FxConditional(base, truex, falsex);
}
else if (sc.CheckToken('='))
{
FxExpression *right = ParseExpressionM(sc, cls);
return new FxAssign(base, right);
}
else
{
return condition;
FxBinary *exp;
FxAssignSelf *left = new FxAssignSelf(sc);
sc.GetToken();
switch (sc.TokenType)
{
case TK_AddEq:
exp = new FxAddSub('+', left, nullptr);
break;
case TK_SubEq:
exp = new FxAddSub('-', left, nullptr);
break;
case TK_MulEq:
exp = new FxMulDiv('*', left, nullptr);
break;
case TK_DivEq:
exp = new FxMulDiv('/', left, nullptr);
break;
case TK_ModEq:
exp = new FxMulDiv('%', left, nullptr);
break;
case TK_LShiftEq:
exp = new FxBinaryInt(TK_LShift, left, nullptr);
break;
case TK_RShiftEq:
exp = new FxBinaryInt(TK_RShift, left, nullptr);
break;
case TK_URShiftEq:
exp = new FxBinaryInt(TK_URShift, left, nullptr);
break;
case TK_AndEq:
exp = new FxBinaryInt('&', left, nullptr);
break;
case TK_XorEq:
exp = new FxBinaryInt('^', left, nullptr);
break;
case TK_OrEq:
exp = new FxBinaryInt('|', left, nullptr);
break;
default:
sc.UnGet();
delete left;
return base;
}
exp->right = ParseExpressionM(sc, cls);
FxAssign *ret = new FxAssign(base, exp);
left->Assignment = ret;
return ret;
}
}
@ -257,6 +323,10 @@ static FxExpression *ParseExpressionB (FScanner &sc, PClassActor *cls)
case '+':
return new FxPlusSign(ParseExpressionA (sc, cls));
case TK_Incr:
case TK_Decr:
return new FxPreIncrDecr(ParseExpressionA(sc, cls), sc.TokenType);
default:
sc.UnGet();
return ParseExpressionA (sc, cls);
@ -312,6 +382,14 @@ static FxExpression *ParseExpressionA (FScanner &sc, PClassActor *cls)
sc.MustGetToken(']');
base_expr = new FxArrayElement(base_expr, index);
}
else if (sc.CheckToken(TK_Incr))
{
return new FxPostIncrDecr(base_expr, TK_Incr);
}
else if (sc.CheckToken(TK_Decr))
{
return new FxPostIncrDecr(base_expr, TK_Decr);
}
else break;
}
@ -357,6 +435,49 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
// a cheap way to get them working when people use "name" instead of 'name'.
return new FxConstant(FName(sc.String), scpos);
}
else if (sc.CheckToken(TK_Bool))
{
sc.MustGetToken('(');
FxExpression *exp = ParseExpressionM(sc, cls);
sc.MustGetToken(')');
return new FxBoolCast(exp);
}
else if (sc.CheckToken(TK_Int))
{
sc.MustGetToken('(');
FxExpression *exp = ParseExpressionM(sc, cls);
sc.MustGetToken(')');
return new FxIntCast(exp);
}
else if (sc.CheckToken(TK_Float))
{
sc.MustGetToken('(');
FxExpression *exp = ParseExpressionM(sc, cls);
sc.MustGetToken(')');
return new FxFloatCast(exp);
}
else if (sc.CheckToken(TK_State))
{
sc.MustGetToken('(');
FxExpression *exp;
if (sc.CheckToken(TK_StringConst))
{
if (sc.String[0] == 0 || sc.Compare("None"))
{
exp = new FxConstant((FState*)nullptr, sc);
}
else
{
exp = new FxMultiNameState(sc.String, sc);
}
}
else
{
exp = new FxRuntimeStateIndex(ParseExpressionM(sc, cls));
}
sc.MustGetToken(')');
return exp;
}
else if (sc.CheckToken(TK_Identifier))
{
FName identifier = FName(sc.String);
@ -374,6 +495,29 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
case NAME_Random2:
return ParseRandom2(sc, cls);
default:
if (cls != nullptr)
{
func = dyn_cast<PFunction>(cls->Symbols.FindSymbol(identifier, true));
// There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work.
if (func != nullptr && identifier != NAME_ACS_NamedExecuteWithResult)
{
args = new FArgumentList;
if (sc.CheckToken('('))
{
sc.UnGet();
ParseFunctionParameters(sc, cls, *args, func, "", nullptr);
}
if (args->Size() == 0)
{
delete args;
args = nullptr;
}
return new FxVMFunctionCall(func, args, sc);
}
}
break;
}
if (sc.CheckToken('('))
@ -392,17 +536,9 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
return ParseAtan2(sc, identifier, cls);
default:
args = new FArgumentList;
func = dyn_cast<PFunction>(cls->Symbols.FindSymbol(identifier, true));
try
{
// There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work.
if (func != NULL && identifier != NAME_ACS_NamedExecuteWithResult)
{
sc.UnGet();
ParseFunctionParameters(sc, cls, *args, func, "", NULL);
return new FxVMFunctionCall(func, args, sc);
}
else if (!sc.CheckToken(')'))
if (!sc.CheckToken(')'))
{
do
{
@ -420,7 +556,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
}
break;
}
}
}
else
{
return new FxIdentifier(identifier, sc);

View file

@ -62,14 +62,16 @@ class FxJumpStatement;
struct FCompileContext
{
TArray<FxJumpStatement *> Jumps;
PPrototype *ReturnProto;
PClassActor *Class;
FCompileContext(PClassActor *cls = nullptr);
FCompileContext(PClassActor *cls = nullptr, PPrototype *ret = nullptr);
PSymbol *FindInClass(FName identifier);
PSymbol *FindGlobal(FName identifier);
void HandleJumps(int token, FxExpression *handler);
void CheckReturn(PPrototype *proto, FScriptPosition &pos);
};
//==========================================================================
@ -170,14 +172,14 @@ struct ExpVal
struct ExpEmit
{
ExpEmit() : RegNum(0), RegType(REGT_NIL), Konst(false), Fixed(false) {}
ExpEmit(int reg, int type) : RegNum(reg), RegType(type), Konst(false), Fixed(false) {}
ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst), Fixed(false) {}
ExpEmit() : RegNum(0), RegType(REGT_NIL), Konst(false), Fixed(false), Final(false) {}
ExpEmit(int reg, int type) : RegNum(reg), RegType(type), Konst(false), Fixed(false), Final(false) {}
ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst), Fixed(false), Final(false) {}
ExpEmit(VMFunctionBuilder *build, int type);
void Free(VMFunctionBuilder *build);
void Reuse(VMFunctionBuilder *build);
BYTE RegNum, RegType, Konst:1, Fixed:1;
BYTE RegNum, RegType, Konst:1, Fixed:1, Final:1;
};
//==========================================================================
@ -201,7 +203,8 @@ public:
virtual FxExpression *Resolve(FCompileContext &ctx);
virtual bool isConstant() const;
virtual void RequestAddress();
virtual bool RequestAddress();
virtual PPrototype *ReturnProto();
virtual VMFunction *GetDirectFunction();
bool IsNumeric() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); }
bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; }
@ -469,6 +472,84 @@ public:
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
// FxPreIncrDecr
//
//==========================================================================
class FxPreIncrDecr : public FxExpression
{
int Token;
FxExpression *Base;
bool AddressRequested;
bool AddressWritable;
public:
FxPreIncrDecr(FxExpression *base, int token);
~FxPreIncrDecr();
FxExpression *Resolve(FCompileContext&);
bool RequestAddress();
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
// FxPostIncrDecr
//
//==========================================================================
class FxPostIncrDecr : public FxExpression
{
int Token;
FxExpression *Base;
public:
FxPostIncrDecr(FxExpression *base, int token);
~FxPostIncrDecr();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
// FxAssign
//
//==========================================================================
class FxAssign : public FxExpression
{
FxExpression *Base;
FxExpression *Right;
bool AddressRequested;
bool AddressWritable;
public:
FxAssign(FxExpression *base, FxExpression *right);
~FxAssign();
FxExpression *Resolve(FCompileContext&);
bool RequestAddress();
ExpEmit Emit(VMFunctionBuilder *build);
ExpEmit Address;
};
//==========================================================================
//
// FxAssignSelf
//
//==========================================================================
class FxAssignSelf : public FxExpression
{
public:
FxAssign *Assignment;
FxAssignSelf(const FScriptPosition &pos);
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
// FxBinary
@ -670,6 +751,7 @@ public:
class FxRandom : public FxExpression
{
protected:
bool EmitTail;
FRandom *rng;
FxExpression *min, *max;
@ -678,7 +760,7 @@ public:
FxRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos);
~FxRandom();
FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto();
ExpEmit Emit(VMFunctionBuilder *build);
};
@ -724,6 +806,7 @@ public:
class FxRandom2 : public FxExpression
{
bool EmitTail;
FRandom * rng;
FxExpression *mask;
@ -732,7 +815,7 @@ public:
FxRandom2(FRandom *, FxExpression *m, const FScriptPosition &pos);
~FxRandom2();
FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto();
ExpEmit Emit(VMFunctionBuilder *build);
};
@ -753,7 +836,7 @@ public:
FxClassMember(FxExpression*, PField*, const FScriptPosition&);
~FxClassMember();
FxExpression *Resolve(FCompileContext&);
void RequestAddress();
bool RequestAddress();
ExpEmit Emit(VMFunctionBuilder *build);
};
@ -796,12 +879,13 @@ class FxArrayElement : public FxExpression
public:
FxExpression *Array;
FxExpression *index;
//bool AddressRequested;
bool AddressRequested;
bool AddressWritable;
FxArrayElement(FxExpression*, FxExpression*);
~FxArrayElement();
FxExpression *Resolve(FCompileContext&);
//void RequestAddress();
bool RequestAddress();
ExpEmit Emit(VMFunctionBuilder *build);
};
@ -836,8 +920,9 @@ public:
class FxActionSpecialCall : public FxExpression
{
FxExpression *Self;
int Special;
bool EmitTail;
FxExpression *Self;
FArgumentList *ArgList;
public:
@ -845,6 +930,7 @@ public:
FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos);
~FxActionSpecialCall();
FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto();
ExpEmit Emit(VMFunctionBuilder *build);
};
@ -875,6 +961,7 @@ public:
class FxVMFunctionCall : public FxExpression
{
bool EmitTail;
PFunction *Function;
FArgumentList *ArgList;
@ -882,13 +969,10 @@ public:
FxVMFunctionCall(PFunction *func, FArgumentList *args, const FScriptPosition &pos);
~FxVMFunctionCall();
FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto();
VMFunction *GetDirectFunction();
ExpEmit Emit(VMFunctionBuilder *build);
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
bool CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit &reg);
unsigned GetArgCount() const { return ArgList == NULL ? 0 : ArgList->Size(); }
PFunction *GetFunction() const { return Function; }
VMFunction *GetVMFunction() const { return Function->Variants[0].Implementation; }
bool IsDirectFunction();
};
//==========================================================================
@ -1010,10 +1094,10 @@ public:
class FxReturnStatement : public FxExpression
{
FxVMFunctionCall *Call;
FxExpression *Value;
public:
FxReturnStatement(FxVMFunctionCall *call, const FScriptPosition &pos);
FxReturnStatement(FxExpression *value, const FScriptPosition &pos);
~FxReturnStatement();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
@ -1058,6 +1142,26 @@ public:
FxExpression *Resolve(FCompileContext&);
};
//==========================================================================
//
// Same as above except for expressions which means it will have to be
// evaluated at runtime
//
//==========================================================================
class FxRuntimeStateIndex : public FxExpression
{
bool EmitTail;
FxExpression *Index;
public:
FxRuntimeStateIndex(FxExpression *index);
~FxRuntimeStateIndex();
FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto();
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
//

File diff suppressed because it is too large Load diff

View file

@ -138,23 +138,30 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c
else if (type == TypeState)
{
// This forces quotation marks around the state name.
sc.MustGetToken(TK_StringConst);
if (sc.String[0] == 0 || sc.Compare("None"))
if (sc.CheckToken(TK_StringConst))
{
x = new FxConstant((FState*)NULL, sc);
}
else if (sc.Compare("*"))
{
if (constant)
if (sc.String[0] == 0 || sc.Compare("None"))
{
x = new FxConstant((FState*)(intptr_t)-1, sc);
x = new FxConstant((FState*)NULL, sc);
}
else if (sc.Compare("*"))
{
if (constant)
{
x = new FxConstant((FState*)(intptr_t)-1, sc);
}
else sc.ScriptError("Invalid state name '*'");
}
else
{
x = new FxMultiNameState(sc.String, sc);
}
else sc.ScriptError("Invalid state name '*'");
}
else
else if (!constant)
{
x = new FxMultiNameState(sc.String, sc);
x = new FxRuntimeStateIndex(ParseExpression(sc, cls));
}
else sc.MustGetToken(TK_StringConst); // This is for the error.
}
else if (type->GetClass() == RUNTIME_CLASS(PClassPointer))
{ // Actor name
@ -191,7 +198,12 @@ static void ParseConstant (FScanner &sc, PSymbolTable *symt, PClassActor *cls)
FxExpression *expr = ParseExpression (sc, cls, true);
sc.MustGetToken(';');
if (!expr->isConstant())
if (expr == nullptr)
{
sc.ScriptMessage("Error while resolving constant definition");
FScriptPosition::ErrorCounter++;
}
else if (!expr->isConstant())
{
sc.ScriptMessage("Constant definition is not a constant");
FScriptPosition::ErrorCounter++;
@ -247,16 +259,24 @@ static void ParseEnum (FScanner &sc, PSymbolTable *symt, PClassActor *cls)
if (sc.CheckToken('='))
{
FxExpression *expr = ParseExpression (sc, cls, true);
if (!expr->isConstant())
if (expr != nullptr)
{
sc.ScriptMessage("'%s' must be constant", symname.GetChars());
FScriptPosition::ErrorCounter++;
if (!expr->isConstant())
{
sc.ScriptMessage("'%s' must be constant", symname.GetChars());
FScriptPosition::ErrorCounter++;
}
else
{
currvalue = static_cast<FxConstant *>(expr)->GetValue().GetInt();
}
delete expr;
}
else
{
currvalue = static_cast<FxConstant *>(expr)->GetValue().GetInt();
sc.ScriptMessage("Error while resolving expression of '%s'", symname.GetChars());
FScriptPosition::ErrorCounter++;
}
delete expr;
}
PSymbolConstNumeric *sym = new PSymbolConstNumeric(symname, TypeSInt32);
sym->Value = currvalue;
@ -568,7 +588,13 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl
if (sc.CheckToken('['))
{
FxExpression *expr = ParseExpression(sc, cls, true);
if (!expr->isConstant())
if (expr == nullptr)
{
sc.ScriptMessage("Error while resolving array size");
FScriptPosition::ErrorCounter++;
maxelems = 1;
}
else if (!expr->isConstant())
{
sc.ScriptMessage("Array size must be a constant");
FScriptPosition::ErrorCounter++;

View file

@ -315,10 +315,10 @@ do_stop:
}
bool hasfinalret;
tcall->Code = ParseActions(sc, state, statestring, bag, tcall->Proto, hasfinalret);
if (!hasfinalret)
tcall->Code = ParseActions(sc, state, statestring, bag, hasfinalret);
if (!hasfinalret && tcall->Code != nullptr)
{
AddImplicitReturn(static_cast<FxSequence*>(tcall->Code), tcall->Proto, sc);
static_cast<FxSequence *>(tcall->Code)->Add(new FxReturnStatement(nullptr, sc));
}
goto endofstate;
}
@ -351,125 +351,37 @@ endofstate:
sc.SetEscape(true); // re-enable escape sequences
}
//==========================================================================
//
// AddImplicitReturn
//
// Adds an implied return; statement to the end of a code sequence.
//
//==========================================================================
void AddImplicitReturn(FxSequence *code, const PPrototype *proto, FScanner &sc)
{
if (code == NULL)
{
return;
}
if (proto == NULL || proto->ReturnTypes.Size() == 0)
{ // Returns nothing. Good. We can safely add an implied return.
code->Add(new FxReturnStatement(NULL, sc));
}
else
{ // Something was returned earlier in the sequence. Make it an error
// instead of adding an implicit one.
sc.ScriptError("Not all paths return a value");
}
}
//==========================================================================
//
// ReturnCheck
//
// If proto1 is NULL, returns proto2. If proto2 is NULL, returns proto1.
// If neither is null, checks if both prototypes define the same return
// types. If not, an error is flagged.
//
//==========================================================================
static PPrototype *ReturnCheck(PPrototype *proto1, PPrototype *proto2, FScanner &sc)
{
if (proto1 == NULL)
{
return proto2;
}
if (proto2 == NULL)
{
return proto1;
}
// A prototype that defines fewer return types can be compatible with
// one that defines more if the shorter one matches the initial types
// for the longer one.
if (proto2->ReturnTypes.Size() < proto1->ReturnTypes.Size())
{ // Make proto1 the shorter one to avoid code duplication below.
swapvalues(proto1, proto2);
}
// If one prototype returns nothing, they both must.
if (proto1->ReturnTypes.Size() == 0)
{
if (proto2->ReturnTypes.Size() == 0)
{
return proto1;
}
proto1 = NULL;
}
else
{
for (unsigned i = 0; i < proto1->ReturnTypes.Size(); ++i)
{
if (proto1->ReturnTypes[i] != proto2->ReturnTypes[i])
{ // Incompatible
proto1 = NULL;
break;
}
}
}
if (proto1 == NULL)
{
sc.ScriptError("Return types are incompatible");
}
return proto1;
}
//==========================================================================
//
// ParseActions
//
// If this action block contains any return statements, the prototype for
// one of them will be returned. This is used for deducing the return type
// of anonymous functions. All called functions passed to return must have
// matching return types.
//
//==========================================================================
static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Baggage &bag,
PPrototype *&retproto, bool &lastwasret)
static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret)
{
FxExpression *add, *cond;
FxExpression *true_part, *false_part = NULL;
PPrototype *true_proto, *false_proto = NULL;
FxExpression *true_part, *false_part = nullptr;
bool true_ret, false_ret = false;
sc.MustGetStringName("(");
cond = ParseExpression(sc, bag.Info);
sc.MustGetStringName(")");
sc.MustGetStringName("{"); // braces are mandatory
true_part = ParseActions(sc, state, statestring, bag, true_proto, true_ret);
true_part = ParseActions(sc, state, statestring, bag, true_ret);
sc.MustGetString();
if (sc.Compare("else"))
{
if (sc.CheckString("if"))
{
false_part = ParseIf(sc, state, statestring, bag, false_proto, false_ret);
false_part = ParseIf(sc, state, statestring, bag, false_ret);
}
else
{
sc.MustGetStringName("{"); // braces are still mandatory
false_part = ParseActions(sc, state, statestring, bag, false_proto, false_ret);
false_part = ParseActions(sc, state, statestring, bag, false_ret);
sc.MustGetString();
}
}
add = new FxIfStatement(cond, true_part, false_part, sc);
retproto = ReturnCheck(retproto, true_proto, sc);
retproto = ReturnCheck(retproto, false_proto, sc);
// If one side does not end with a return, we don't consider the if statement
// to end with a return. If the else case is missing, it can never be considered
// as ending with a return.
@ -480,11 +392,9 @@ static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Ba
return add;
}
static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring, Baggage &bag,
PPrototype *&retproto, bool &lastwasret)
static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret)
{
FxExpression *cond, *code;
PPrototype *proto;
bool ret;
sc.MustGetStringName("(");
@ -492,24 +402,21 @@ static FxExpression *ParseWhile(FScanner &sc, FState state, FString statestring,
sc.MustGetStringName(")");
sc.MustGetStringName("{"); // Enforce braces like for if statements.
code = ParseActions(sc, state, statestring, bag, proto, ret);
code = ParseActions(sc, state, statestring, bag, ret);
sc.MustGetString();
retproto = ReturnCheck(retproto, proto, sc);
lastwasret = false; // A while loop always jumps back.
return new FxWhileLoop(cond, code, sc);
}
static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestring, Baggage &bag,
PPrototype *&retproto, bool &lastwasret)
static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret)
{
FxExpression *cond, *code;
PPrototype *proto;
bool ret;
sc.MustGetStringName("{"); // Enforce braces like for if statements.
code = ParseActions(sc, state, statestring, bag, proto, ret);
code = ParseActions(sc, state, statestring, bag, ret);
sc.MustGetStringName("while");
sc.MustGetStringName("(");
@ -518,20 +425,17 @@ static FxExpression *ParseDoWhile(FScanner &sc, FState state, FString statestrin
sc.MustGetStringName(";");
sc.MustGetString();
retproto = ReturnCheck(retproto, proto, sc);
lastwasret = false;
return new FxDoWhileLoop(cond, code, sc);
}
static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, Baggage &bag,
PPrototype *&retproto, bool &lastwasret)
static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &lastwasret)
{
FxExpression *init = nullptr;
FxExpression *cond = nullptr;
FxExpression *iter = nullptr;
FxExpression *code = nullptr;
PPrototype *proto;
bool ret;
// Parse the statements.
@ -539,7 +443,8 @@ static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, B
sc.MustGetString();
if (!sc.Compare(";"))
{
init = ParseAction(sc, state, statestring, bag); // That's all DECORATE can handle for now.
sc.UnGet();
init = ParseExpression(sc, bag.Info);
sc.MustGetStringName(";");
}
sc.MustGetString();
@ -552,30 +457,28 @@ static FxExpression *ParseFor(FScanner &sc, FState state, FString statestring, B
sc.MustGetString();
if (!sc.Compare(")"))
{
iter = ParseAction(sc, state, statestring, bag);
sc.UnGet();
iter = ParseExpression(sc, bag.Info);
sc.MustGetStringName(")");
}
// Now parse the loop's content.
sc.MustGetStringName("{"); // Enforce braces like for if statements.
code = ParseActions(sc, state, statestring, bag, proto, ret);
code = ParseActions(sc, state, statestring, bag, ret);
sc.MustGetString();
retproto = ReturnCheck(retproto, proto, sc);
lastwasret = false;
return new FxForLoop(init, cond, iter, code, sc);
}
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag,
PPrototype *&retproto, bool &endswithret)
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &endswithret)
{
// If it's not a '{', then it should be a single action.
// Otherwise, it's a sequence of actions.
if (!sc.Compare("{"))
{
FxVMFunctionCall *call = ParseAction(sc, state, statestring, bag);
retproto = call->GetVMFunction()->Proto;
endswithret = true;
return new FxReturnStatement(call, sc);
}
@ -583,7 +486,6 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
const FScriptPosition pos(sc);
FxSequence *seq = NULL;
PPrototype *proto = NULL;
bool lastwasret = false;
sc.MustGetString();
@ -593,38 +495,31 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
lastwasret = false;
if (sc.Compare("if"))
{ // Handle an if statement
add = ParseIf(sc, state, statestring, bag, proto, lastwasret);
add = ParseIf(sc, state, statestring, bag, lastwasret);
}
else if (sc.Compare("while"))
{ // Handle a while loop
add = ParseWhile(sc, state, statestring, bag, proto, lastwasret);
add = ParseWhile(sc, state, statestring, bag, lastwasret);
}
else if (sc.Compare("do"))
{ // Handle a do-while loop
add = ParseDoWhile(sc, state, statestring, bag, proto, lastwasret);
add = ParseDoWhile(sc, state, statestring, bag, lastwasret);
}
else if (sc.Compare("for"))
{ // Handle a for loop
add = ParseFor(sc, state, statestring, bag, proto, lastwasret);
add = ParseFor(sc, state, statestring, bag, lastwasret);
}
else if (sc.Compare("return"))
{ // Handle a return statement
lastwasret = true;
FxVMFunctionCall *retexp = NULL;
PPrototype *retproto;
FxExpression *retexp = nullptr;
sc.MustGetString();
if (!sc.Compare(";"))
{
retexp = ParseAction(sc, state, statestring, bag);
sc.UnGet();
retexp = ParseExpression(sc, bag.Info);
sc.MustGetStringName(";");
retproto = retexp->GetVMFunction()->Proto;
}
else
{ // Returning nothing; we still need a prototype for that.
TArray<PType *> notypes(0);
retproto = NewPrototype(notypes, notypes);
}
proto = ReturnCheck(proto, retproto, sc);
sc.MustGetString();
add = new FxReturnStatement(retexp, sc);
}
@ -641,8 +536,9 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
sc.MustGetString();
}
else
{ // Handle a regular action function call
add = ParseAction(sc, state, statestring, bag);
{ // Handle a regular expression
sc.UnGet();
add = ParseExpression(sc, bag.Info);
sc.MustGetStringName(";");
sc.MustGetString();
}
@ -657,7 +553,6 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
}
}
endswithret = lastwasret;
retproto = proto;
return seq;
}

View file

@ -1239,6 +1239,19 @@ void DCanvas::Clear (int left, int top, int right, int bottom, int palcolor, uin
}
}
//==========================================================================
//
// no-ops. This is so that renderer backends can better manage the
// processing of the subsector drawing in the automap
//
//==========================================================================
void DCanvas::StartSimplePolys()
{}
void DCanvas::FinishSimplePolys()
{}
//==========================================================================
//
// DCanvas :: FillSimplePoly

View file

@ -216,6 +216,9 @@ public:
// Fill an area with a texture
virtual void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin=false);
virtual void StartSimplePolys();
virtual void FinishSimplePolys();
// Fill a simple polygon with a texture
virtual void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley, DAngle rotation,

View file

@ -1141,7 +1141,7 @@ void Win32GLFrameBuffer::ReleaseResources ()
void Win32GLFrameBuffer::SetVSync (bool vsync)
{
if (vsyncfunc != NULL) vsyncfunc(vsync);
if (vsyncfunc != NULL) vsyncfunc(vsync ? 1 : 0);
}
void Win32GLFrameBuffer::SwapBuffers()

View file

@ -397,6 +397,7 @@ D62DCA9EC226DE49108D5DD9271F7631 // Cheogsh 2 map04
E89CCC7E155F1032F693359CC219BE6C // hexen.wad map30
B9DFF13207EACAC675C71D82624D0007 // XtheaterIII map01
6941BDC2F80C0FEBE34EFA23D5FB72B7 // sonic.wad map10
{
DisablePushWindowCheck
}
@ -430,6 +431,22 @@ C98F79709BD7E0E4C19026AB9575EC6F // cc-cod.zip:codlev.wad map07
maskedmidtex
}
7B82B12A6990E09553B12FDB4E3824A0 // hti.wad map01
{
teleport
}
8570AA0D6737C0A19DB66767764F157F // sonic.wad map04
{
noslopeid
}
05AA32F1D2220A462DCDA245ED22B94B // sonic.wad map09
{
polyobj
}
D7F6E9F08C39A17026349A04F8C0B0BE // Return to Hadron, e1m9
19D03FFC875589E21EDBB7AB74EF4AEF // Return to Hadron, e1m9, 2016.01.03 update
{

View file

@ -2069,6 +2069,8 @@ CMPTMNU_SILENTINSTANTFLOORS = "Inst. moving floors are not silent";
CMPTMNU_SECTORSOUNDS = "Sector sounds use center as source";
CMPTMNU_SOUNDCUTOFF = "Sounds stop when actor vanishes";
CMPTMNU_SOUNDTARGET = "Use original sound target handling";
CMPTMNU_TELEPORT = "Scripted teleports don't trigger sector actions";
CMPTMNU_PUSHWINDOW = "Non-blocking lines can be pushed";
// Sound Options
SNDMNU_TITLE = "SOUND OPTIONS";
@ -2197,6 +2199,7 @@ OPTVAL_PLAYER = "Player";
OPTVAL_MAP = "Map";
OPTVAL_SCALETO640X400 = "Scale to 640x400";
OPTVAL_PIXELDOUBLE = "Pixel double";
OPTVAL_PIXELQUADRUPLE = "Pixel quadruple";
OPTVAL_CURRENTWEAPON = "Current weapon";
OPTVAL_AVAILABLEWEAPONS = "Available weapons";
OPTVAL_ALLWEAPONS = "All weapons";
@ -2231,6 +2234,7 @@ OPTVAL_ANIMATED = "Animated";
OPTVAL_ROTATED = "Rotated";
OPTVAL_MAPDEFINEDCOLORSONLY = "Map defined colors only";
OPTVAL_DOUBLE = "Double";
OPTVAL_QUADRUPLE = "Quadruple";
OPTVAL_ITEMPICKUP = "Item Pickup";
OPTVAL_OBITUARIES = "Obituaries";
OPTVAL_CRITICALMESSAGES = "Critical Messages";
@ -2621,6 +2625,7 @@ GLPREFMNU_VRQUADSTEREO = "Enable Quad Stereo";
GLPREFMNU_MULTISAMPLE = "Multisample";
GLPREFMNU_TONEMAP = "Tonemap Mode";
GLPREFMNU_BLOOM = "Bloom effect";
GLPREFMNU_LENS = "Lens distortion effect";
// Option Values
OPTVAL_SMART = "Smart";

View file

@ -773,7 +773,7 @@ OptionMenu "HUDOptions"
Option "$HUDMNU_GROWCROSSHAIR", "crosshairgrow", "OnOff"
ColorPicker "$HUDMNU_CROSSHAIRCOLOR", "crosshaircolor"
Option "$HUDMNU_CROSSHAIRHEALTH", "crosshairhealth", "OnOff"
Option "$HUDMNU_CROSSHAIRSCALE", "crosshairscale", "OnOff"
Slider "$HUDMNU_CROSSHAIRSCALE", "crosshairscale", 0.0, 2.0, 0.05, 2
StaticText " "
Option "$HUDMNU_NAMETAGS", "displaynametags", "DisplayTagsTypes"
Option "$HUDMNU_NAMETAGCOLOR", "nametagcolor", "TextColors", "displaynametags"
@ -804,6 +804,7 @@ OptionValue "AltHUDScale"
0, "$OPTVAL_OFF"
1, "$OPTVAL_SCALETO640X400"
2, "$OPTVAL_PIXELDOUBLE"
3, "$OPTVAL_PIXELQUADRUPLE"
}
OptionValue "AltHUDAmmo"
@ -1120,6 +1121,7 @@ OptionValue ScaleValues
0, "$OPTVAL_OFF"
1, "$OPTVAL_ON"
2, "$OPTVAL_DOUBLE"
3, "$OPTVAL_QUADRUPLE"
}
OptionValue MessageLevels
@ -1331,6 +1333,8 @@ OptionMenu "CompatibilityOptions"
Option "$CMPTMNU_FLOORMOVE", "compat_floormove", "YesNo"
Option "$CMPTMNU_POINTONLINE", "compat_pointonline", "YesNo"
Option "$CMPTMNU_MULTIEXIT", "compat_multiexit", "YesNo"
Option "$CMPTMNU_TELEPORT", "compat_teleport", "YesNo"
Option "$CMPTMNU_PUSHWINDOW", "compat_pushwindow", "YesNo"
StaticText " "
StaticText "$CMPTMNU_PHYSICSBEHAVIOR",1

View file

@ -220,4 +220,5 @@ OptionMenu "GLPrefOptions"
Option "$GLPREFMNU_MULTISAMPLE", gl_multisample, "Multisample"
Option "$GLPREFMNU_TONEMAP", gl_tonemap, "TonemapModes"
Option "$GLPREFMNU_BLOOM", gl_bloom, "OnOff"
Option "$GLPREFMNU_LENS", gl_lens, "OnOff"
}

View file

@ -1,9 +0,0 @@
in vec4 PositionInProjection;
out vec2 TexCoord;
void main()
{
gl_Position = PositionInProjection;
TexCoord = PositionInProjection.xy * 0.5 + 0.5;
}

View file

@ -0,0 +1,58 @@
/*
Original Lens Distortion Algorithm from SSontech
http://www.ssontech.com/content/lensalg.htm
If (u,v) are the coordinates of a feature in the undistorted perfect
image plane, then (u', v') are the coordinates of the feature on the
distorted image plate, ie the scanned or captured image from the
camera. The distortion occurs radially away from the image center,
with correction for the image aspect ratio (image_aspect = physical
image width/height), as follows:
r2 = image_aspect*image_aspect*u*u + v*v
f = 1 + r2*(k + kcube*sqrt(r2))
u' = f*u
v' = f*v
The constant k is the distortion coefficient that appears on the lens
panel and through Sizzle. It is generally a small positive or negative
number under 1%. The constant kcube is the cubic distortion value found
on the image preprocessor's lens panel: it can be used to undistort or
redistort images, but it does not affect or get computed by the solver.
When no cubic distortion is needed, neither is the square root, saving
time.
Chromatic Aberration example,
using red distord channel with green and blue undistord channel:
k = vec3(-0.15, 0.0, 0.0);
kcube = vec3(0.15, 0.0, 0.0);
*/
in vec2 TexCoord;
out vec4 FragColor;
uniform sampler2D InputTexture;
uniform float Aspect; // image width/height
uniform float Scale; // 1/max(f)
uniform vec4 k; // lens distortion coefficient
uniform vec4 kcube; // cubic distortion value
void main()
{
vec2 position = (TexCoord - vec2(0.5));
vec2 p = vec2(position.x * Aspect, position.y);
float r2 = dot(p, p);
vec3 f = vec3(1.0) + r2 * (k.rgb + kcube.rgb * sqrt(r2));
vec3 x = f * position.x * Scale + 0.5;
vec3 y = f * position.y * Scale + 0.5;
vec3 c;
c.r = texture(InputTexture, vec2(x.r, y.r)).r;
c.g = texture(InputTexture, vec2(x.g, y.g)).g;
c.b = texture(InputTexture, vec2(x.b, y.b)).b;
FragColor = vec4(c, 1.0);
}

View file

@ -1,9 +1,11 @@
in vec4 PositionInProjection;
in vec2 UV;
uniform vec2 UVScale;
out vec2 TexCoord;
void main()
{
gl_Position = PositionInProjection;
TexCoord = PositionInProjection.xy * 0.5 + 0.5;
TexCoord = UV * UVScale;
}

View file

@ -1,9 +0,0 @@
in vec4 PositionInProjection;
out vec2 TexCoord;
void main()
{
gl_Position = PositionInProjection;
TexCoord = PositionInProjection.xy * 0.5 + 0.5;
}

View file

@ -251,3 +251,13 @@ enum
466 = 0, Floor_TransferTrigger(0)
467 = 0, Floor_TransferNumeric(0)
468 = 0, FloorAndCeiling_LowerRaise(0)
469 = 0, HealThing(0)
470 = 0, Sector_SetRotation(0)
471 = 0, Sector_SetFloorPanning(0)
472 = 0, Sector_SetCeilingPanning(0)
473 = 0, Light_MinNeighbor(0)
474 = 0, Polyobj_Stop(0)
475 = 0, Plat_RaiseAndStayTx0(0)
476 = 0, Plat_UpByValueStayTx(0)
477 = 0, ACS_ExecuteAlways(0)
478 = 0, Thing_Remove(0)