From 3f17d64f90c0795b5d70ecdbe72fdae88a3b32ab Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 24 Sep 2016 09:42:35 +0200 Subject: [PATCH 01/51] - fixed pitch comparison in visibility checking. --- src/p_mobj.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 8d6d75237..4369ae9cc 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1052,7 +1052,7 @@ bool AActor::IsInsideVisibleAngles() const angleend = temp; } - if (pitchstart > angleend) + if (pitchstart > pitchend) { DAngle temp = pitchstart; pitchstart = pitchend; From a419b581a8744ead4b0c16833cd67113858ecc2f Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 24 Sep 2016 13:15:45 +0300 Subject: [PATCH 02/51] Fixed compilation on macOS --- src/m_swap.h | 15 +++++++++++++++ src/serializer.cpp | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/m_swap.h b/src/m_swap.h index f5606e59c..ddcf8eaf9 100644 --- a/src/m_swap.h +++ b/src/m_swap.h @@ -46,6 +46,11 @@ inline short LittleShort(int x) return OSSwapLittleToHostInt16((uint16_t)x); } +inline unsigned short LittleShort(unsigned int x) +{ + return OSSwapLittleToHostInt16((uint16_t)x); +} + inline int LittleLong(int x) { return OSSwapLittleToHostInt32((uint32_t)x); @@ -56,6 +61,16 @@ inline unsigned int LittleLong(unsigned int x) return OSSwapLittleToHostInt32(x); } +inline int LittleLong(long x) +{ + return OSSwapLittleToHostInt32((uint32_t)x); +} + +inline unsigned int LittleLong(unsigned long x) +{ + return OSSwapLittleToHostInt32((uint32_t)x); +} + inline short BigShort(short x) { return (short)OSSwapBigToHostInt16((uint16_t)x); diff --git a/src/serializer.cpp b/src/serializer.cpp index a23459ced..445a3b22b 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -1294,7 +1294,7 @@ FSerializer &SerializePointer(FSerializer &arc, const char *key, T *&value, T ** assert(base != nullptr); if (arc.isReading() || !arc.w->inObject() || defval == nullptr || value != *defval) { - ptrdiff_t vv = value == nullptr ? -1 : value - base; + int64_t vv = value == nullptr ? -1 : value - base; Serialize(arc, key, vv, nullptr); value = vv < 0 ? nullptr : base + vv; } From 74b8e9f28660f62f10825c9e502f5c8428924596 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Sat, 24 Sep 2016 10:26:21 -0500 Subject: [PATCH 03/51] - Don't use Normalized180() on angles. This could result in ranges being wrongly inverted. - Fixed properties not having the proper indices. - Use ViewPos-to-actor instead of measuring actor-to-actor. - Use the actual camera instead of the actor so camera textures can work. --- src/p_mobj.cpp | 25 ++++++++++++------------- src/thingdef/thingdef_properties.cpp | 4 ++-- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 4369ae9cc..400b41798 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -70,6 +70,7 @@ #include "p_spec.h" #include "p_checkposition.h" #include "serializer.h" +#include "r_utility.h" // MACROS ------------------------------------------------------------------ @@ -1040,11 +1041,11 @@ bool AActor::IsInsideVisibleAngles() const if (players[consoleplayer].camera == nullptr) return true; - DAngle anglestart = VisibleStartAngle.Normalized180(); - DAngle angleend = VisibleEndAngle.Normalized180(); - DAngle pitchstart = VisibleStartPitch.Normalized180(); - DAngle pitchend = VisibleEndPitch.Normalized180(); - + DAngle anglestart = VisibleStartAngle; + DAngle angleend = VisibleEndAngle; + DAngle pitchstart = VisibleStartPitch; + DAngle pitchend = VisibleEndPitch; + if (anglestart > angleend) { DAngle temp = anglestart; @@ -1058,22 +1059,20 @@ bool AActor::IsInsideVisibleAngles() const pitchstart = pitchend; pitchend = temp; } + - player_t* pPlayer = players[consoleplayer].camera->player; + AActor *mo = players[consoleplayer].camera; - if (pPlayer && pPlayer->mo) + if (mo != nullptr) { - AActor *mo = pPlayer->mo; - DVector3 diffang = Vec3To(mo); + + DVector3 diffang = ViewPos - Pos(); DAngle to = diffang.Angle(); if (!(renderflags & RF_ABSMASKANGLE)) to = deltaangle(Angles.Yaw, to); - // Note that this check is inversed due to only being able to vectorize - // from one way (this actor to the player). It still means to pass - // if the player is within the visible angles. - if ((to <= anglestart || to >= angleend)) + if ((to >= anglestart && to <= angleend)) { to = diffang.Pitch(); if (!(renderflags & RF_ABSMASKPITCH)) diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 8ada05aa6..927e3e537 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1437,7 +1437,7 @@ DEFINE_PROPERTY(spriterotation, F, Actor) DEFINE_PROPERTY(visibleangles, Ff, Actor) { PROP_DOUBLE_PARM(visstart, 0); - PROP_DOUBLE_PARM(visend, 0); + PROP_DOUBLE_PARM(visend, 1); defaults->VisibleStartAngle = visstart; defaults->VisibleEndAngle = visend; } @@ -1448,7 +1448,7 @@ DEFINE_PROPERTY(visibleangles, Ff, Actor) DEFINE_PROPERTY(visiblepitch, Ff, Actor) { PROP_DOUBLE_PARM(visstart, 0); - PROP_DOUBLE_PARM(visend, 0); + PROP_DOUBLE_PARM(visend, 1); defaults->VisibleStartPitch = visstart; defaults->VisibleEndPitch = visend; } From 6a6a0e8017109fbf1256bccf878277cf6e75403e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 25 Sep 2016 01:28:27 +0200 Subject: [PATCH 04/51] - removed some more hubtravel related player start fudging. * do not skip the player_t init when travelling in a hub. The old player may still be needed in some edge cases. This applies only to singleplayer for now. The multiplayer version still needs reviewing. I left it alone because it may shuffle players around which is not wanted when doing hub travelling. * do not spawn two temp players in G_FinishTravel. Instead handle the case where no player_t::mo can be found gracefully by adding a few nullptr checks. This temp player served no real purpose except for having a valid pointer. The actual start position was retrieved from somewhere else. --- src/g_level.cpp | 29 +++++++++++++---------------- src/p_saveg.cpp | 11 ++++------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/g_level.cpp b/src/g_level.cpp index dcf97ba4f..90b31138d 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1207,29 +1207,23 @@ void G_FinishTravel () pnum = int(pawn->player - players); pawn->ChangeStatNum (STAT_PLAYER); pawndup = pawn->player->mo; - start = NULL; assert (pawn != pawndup); - if (pawndup == NULL) - { // Oh no! there was no start for this player! - start = G_PickPlayerStart(pnum, PPS_FORCERANDOM); - if (start != NULL) pawndup = P_SpawnPlayer(start, pnum, (level.flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0); - if (pawndup == NULL) - { - pawn->flags |= MF_NOSECTOR | MF_NOBLOCKMAP; - pawn->Destroy(); - continue; - } - } + start = G_PickPlayerStart(pnum, 0); if (start == NULL) { - start = G_PickPlayerStart(pnum, 0); - if (start == NULL) + if (pawndup != nullptr) { Printf(TEXTCOLOR_RED "No player %d start to travel to!\n", pnum + 1); // Move to the coordinates this player had when they left the level. pawn->SetXYZ(pawndup->Pos()); } + else + { + // Could not find a start for this player at all. This really should never happen but if it does, let's better abort. + DThinker::DestroyThinkersInList(STAT_TRAVELLING); + I_Error ("No player %d start to travel to!\n", pnum + 1); + } } oldpawn = pawndup; @@ -1266,8 +1260,11 @@ void G_FinishTravel () pawn->player->camera = pawn; pawn->player->viewheight = pawn->ViewHeight; pawn->flags2 &= ~MF2_BLASTED; - DObject::StaticPointerSubstitution (oldpawn, pawn); - oldpawn->Destroy(); + if (oldpawn != nullptr) + { + DObject::StaticPointerSubstitution (oldpawn, pawn); + oldpawn->Destroy(); + } if (pawndup != NULL) { pawndup->Destroy(); diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 465760137..2382d3ede 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -537,7 +537,7 @@ void P_SerializeSounds(FSerializer &arc) //========================================================================== void CopyPlayer(player_t *dst, player_t *src, const char *name); -static void ReadOnePlayer(FSerializer &arc, bool skipload); +static void ReadOnePlayer(FSerializer &arc); static void ReadMultiplePlayers(FSerializer &arc, int numPlayers, int numPlayersNow, bool skipload); static void SpawnExtraPlayers(); @@ -594,7 +594,7 @@ void P_SerializePlayers(FSerializer &arc, bool skipload) // first player present, no matter what their name. if (numPlayers == 1) { - ReadOnePlayer(arc, skipload); + ReadOnePlayer(arc); } else { @@ -617,7 +617,7 @@ void P_SerializePlayers(FSerializer &arc, bool skipload) // //========================================================================== -static void ReadOnePlayer(FSerializer &arc, bool skipload) +static void ReadOnePlayer(FSerializer &arc) { int i; const char *name = NULL; @@ -636,10 +636,7 @@ static void ReadOnePlayer(FSerializer &arc, bool skipload) didIt = true; player_t playerTemp; playerTemp.Serialize(arc); - if (!skipload) - { - CopyPlayer(&players[i], &playerTemp, name); - } + CopyPlayer(&players[i], &playerTemp, name); } else { From 92d0043a81705cb4fa6d1a78552ba50f16b7e207 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 25 Sep 2016 09:23:44 +0200 Subject: [PATCH 05/51] - undid part of the last commit and hopefully corrected it for good now. We have to be extremely careful with the player data, because there's just too much code littered around that has certain expectations about what needs to be present and what not. Obviously, when travelling in a hub, the player_t should be retained from the previous level. But we still have to set player_t::mo to the PlayerPawn from the savegame so that G_UnsnapshotLevel doesn't prematurely delete it and all associated voodoo dolls, because it checks player_t::mo to decide whether a player is valid or not. The actual deletion of this redundant PlayerPawn should only be done in G_FinishTravel, after the actual player has been fully set up --- src/p_saveg.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 2382d3ede..9bb9f82e8 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -537,7 +537,7 @@ void P_SerializeSounds(FSerializer &arc) //========================================================================== void CopyPlayer(player_t *dst, player_t *src, const char *name); -static void ReadOnePlayer(FSerializer &arc); +static void ReadOnePlayer(FSerializer &arc, bool skipload); static void ReadMultiplePlayers(FSerializer &arc, int numPlayers, int numPlayersNow, bool skipload); static void SpawnExtraPlayers(); @@ -594,7 +594,7 @@ void P_SerializePlayers(FSerializer &arc, bool skipload) // first player present, no matter what their name. if (numPlayers == 1) { - ReadOnePlayer(arc); + ReadOnePlayer(arc, skipload); } else { @@ -617,7 +617,7 @@ void P_SerializePlayers(FSerializer &arc, bool skipload) // //========================================================================== -static void ReadOnePlayer(FSerializer &arc) +static void ReadOnePlayer(FSerializer &arc, bool skipload) { int i; const char *name = NULL; @@ -636,7 +636,15 @@ static void ReadOnePlayer(FSerializer &arc) didIt = true; player_t playerTemp; playerTemp.Serialize(arc); - CopyPlayer(&players[i], &playerTemp, name); + if (!skipload) + { + CopyPlayer(&players[i], &playerTemp, name); + } + else + { + // we need the player actor, so that G_FinishTravel can destroy it later. + players[i].mo = playerTemp.mo; + } } else { @@ -750,6 +758,13 @@ static void ReadMultiplePlayers(FSerializer &arc, int numPlayers, int numPlayers } } } + else + { + for (i = 0; i < MAXPLAYERS; ++i) + { + players[i].mo = playertemp[i].mo; + } + } delete[] tempPlayerUsed; delete[] playertemp; From f4462a7b93312a9b50e8011a68ef0967326d08ed Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 25 Sep 2016 09:43:17 +0200 Subject: [PATCH 06/51] - fixed: Any DSectorEffect thinker must be placed into STAT_SECTOREFFECT. The slot had been there forever to address this same problem but only one of the two constructors actually set it, too bad that it was the wrong one... This is something that normally won't be noticed. But if some actor is spawned on a moving platform, with both thinkers on the same statnum it means that the order of execution is not correct with the platform being done first, resulting in the actor to 'jump' while the platform is moving. To prevent this it is necessary that all sector movers only tick after all actors have completed their thinking turn. --- src/dsectoreffect.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dsectoreffect.cpp b/src/dsectoreffect.cpp index 78e00e6b0..815b49dc4 100644 --- a/src/dsectoreffect.cpp +++ b/src/dsectoreffect.cpp @@ -60,6 +60,7 @@ void DSectorEffect::Destroy() } DSectorEffect::DSectorEffect (sector_t *sector) + : DThinker(STAT_SECTOREFFECT) { m_Sector = sector; } From a7044c9a8b0848fc9d6158b98ac4cef5ed0e5469 Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Sun, 25 Sep 2016 15:57:50 -0400 Subject: [PATCH 07/51] Remove quotation marks that cause trouble with older versions of CMake. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 485d6ea03..97c44355a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,7 +55,7 @@ function( add_pk3 PK3_NAME PK3_DIR ) add_custom_target( ${PK3_TARGET} ALL COMMAND ${CMAKE_COMMAND} -E touch $ DEPENDS ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} - SOURCES "${PK3_SRCS}") + SOURCES ${PK3_SRCS}) endfunction() # Macro for building libraries without debugging information From 750c1949597179a1bb60daaad4fa71d80ecc7e47 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 26 Sep 2016 01:38:25 +0200 Subject: [PATCH 08/51] - changed order of SwapBuffers and glFinish call. The new order with glFinish coming last is recommended by OpenGL and it fixes a stalling problem with portals and camera textures visible at the same time. - check and use WGL_EXT_swap_control_tear extension. The above change makes the system always wait for a full vsync with a wglSwapInterval of 1, so it now uses the official extension that enables adaptive vsync. Hopefully this also works on the cards where the old setup did not. --- src/gl/scene/gl_portal.cpp | 6 +++--- src/gl/system/gl_framebuffer.cpp | 2 +- src/win32/win32gliface.cpp | 34 +++++++++++++++++++++++++++----- src/win32/win32gliface.h | 1 + 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/gl/scene/gl_portal.cpp b/src/gl/scene/gl_portal.cpp index f34b5e23f..4a7fa9d7a 100644 --- a/src/gl/scene/gl_portal.cpp +++ b/src/gl/scene/gl_portal.cpp @@ -176,12 +176,12 @@ void GLPortal::DrawPortalStencil() bool GLPortal::Start(bool usestencil, bool doquery) { rendered_portals++; - PortalAll.Clock(); +// PortalAll.Clock(); if (usestencil) { if (!gl_portals) { - PortalAll.Unclock(); +// PortalAll.Unclock(); return false; } @@ -297,7 +297,7 @@ bool GLPortal::Start(bool usestencil, bool doquery) GLRenderer->mCurrentPortal = this; if (PrevPortal != NULL) PrevPortal->PushState(); - PortalAll.Unclock(); +// PortalAll.Unclock(); return true; } diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index 94eba0817..08aca521f 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -209,13 +209,13 @@ void OpenGLFrameBuffer::Swap() { Finish.Reset(); Finish.Clock(); - glFinish(); if (needsetgamma) { //DoSetGamma(); needsetgamma = false; } SwapBuffers(); + glFinish(); Finish.Unclock(); swapped = true; FHardwareTexture::UnbindAll(); diff --git a/src/win32/win32gliface.cpp b/src/win32/win32gliface.cpp index 7ca001e1e..5d68d8427 100644 --- a/src/win32/win32gliface.cpp +++ b/src/win32/win32gliface.cpp @@ -37,7 +37,9 @@ extern int NewWidth, NewHeight, NewBits, DisplayBits; // these get used before GLEW is initialized so we have to use separate pointers with different names PFNWGLCHOOSEPIXELFORMATARBPROC myWglChoosePixelFormatARB; // = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); PFNWGLCREATECONTEXTATTRIBSARBPROC myWglCreateContextAttribsARB; -PFNWGLSWAPINTERVALEXTPROC vsyncfunc; +PFNWGLSWAPINTERVALEXTPROC myWglSwapIntervalExtProc; + + CUSTOM_CVAR(Bool, gl_debug, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) @@ -933,10 +935,32 @@ Win32GLFrameBuffer::Win32GLFrameBuffer(void *hMonitor, int width, int height, in vid_renderer = 0; return; } - - vsyncfunc = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); - HDC hDC = GetDC(Window); + const char *wglext = nullptr; + + myWglSwapIntervalExtProc = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); + auto myWglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); + if (myWglGetExtensionsStringARB) + { + wglext = myWglGetExtensionsStringARB(hDC); + } + else + { + auto myWglGetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT"); + if (myWglGetExtensionsStringEXT) + { + wglext = myWglGetExtensionsStringEXT(); + } + } + SwapInterval = 1; + if (wglext != nullptr) + { + if (strstr(wglext, "WGL_EXT_swap_control_tear")) + { + SwapInterval = -1; + } + } + m_supportsGamma = !!GetDeviceGammaRamp(hDC, (void *)m_origGamma); ReleaseDC(Window, hDC); } @@ -1091,7 +1115,7 @@ void Win32GLFrameBuffer::ReleaseResources () void Win32GLFrameBuffer::SetVSync (bool vsync) { - if (vsyncfunc != NULL) vsyncfunc(vsync ? 1 : 0); + if (myWglSwapIntervalExtProc != NULL) myWglSwapIntervalExtProc(vsync ? SwapInterval : 0); } void Win32GLFrameBuffer::SwapBuffers() diff --git a/src/win32/win32gliface.h b/src/win32/win32gliface.h index 6320e2903..e767073c4 100644 --- a/src/win32/win32gliface.h +++ b/src/win32/win32gliface.h @@ -148,6 +148,7 @@ protected: int m_Lock; char m_displayDeviceNameBuffer[CCHDEVICENAME]; char *m_displayDeviceName; + int SwapInterval; friend class Win32GLVideo; From 40f0dbf51cc4379141f607f6b33a242312eba362 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Tue, 27 Sep 2016 16:27:31 -0500 Subject: [PATCH 09/51] Fixed: Y and Z were flipped for sound velocity --- src/s_sound.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 866af965a..06df0dbad 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -753,8 +753,8 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector, if (type == SOURCE_Actor && actor != NULL) { vel->X = float(actor->Vel.X * TICRATE); - vel->Y = float(actor->Vel.Y * TICRATE); - vel->Z = float(actor->Vel.Z * TICRATE); + vel->Y = float(actor->Vel.Z * TICRATE); + vel->Z = float(actor->Vel.Y * TICRATE); } else { From 59e52b3e9be0b7f7248a3a863ad4c956e2430ea0 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Tue, 27 Sep 2016 18:40:36 -0500 Subject: [PATCH 10/51] Fixed: Heretic platforms make a mid-move sound, unlike Doom's --- wadsrc/static/filter/game-heretic/sndinfo.txt | 1 + wadsrc/static/filter/game-heretic/sndseq.txt | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 wadsrc/static/filter/game-heretic/sndseq.txt diff --git a/wadsrc/static/filter/game-heretic/sndinfo.txt b/wadsrc/static/filter/game-heretic/sndinfo.txt index b9f1fd7c3..53017a49a 100644 --- a/wadsrc/static/filter/game-heretic/sndinfo.txt +++ b/wadsrc/static/filter/game-heretic/sndinfo.txt @@ -151,6 +151,7 @@ $alias switches/exitbutn switches/normbutn // Heretic has no special exit button plats/pt1_strt pstart plats/pt1_stop pstop plats/pt1_mid dormov +plats/pt2_mid stnmov // // Door Sounds diff --git a/wadsrc/static/filter/game-heretic/sndseq.txt b/wadsrc/static/filter/game-heretic/sndseq.txt new file mode 100644 index 000000000..405ebc8fb --- /dev/null +++ b/wadsrc/static/filter/game-heretic/sndseq.txt @@ -0,0 +1,5 @@ +:Platform + playuntildone plats/pt1_strt + playrepeat plats/pt2_mid + stopsound plats/pt1_stop +end From e3be6e4819ee4c3a6736b8e264144240d5fb8206 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Tue, 27 Sep 2016 18:58:09 -0500 Subject: [PATCH 11/51] Fixed: The menu no longer refreshed the screen border --- src/menu/menu.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 5e5124b2a..7e938230e 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -717,7 +717,11 @@ void M_Drawer (void) if (DMenu::CurrentMenu != NULL && menuactive != MENU_Off) { - if (DMenu::CurrentMenu->DimAllowed()) screen->Dim(fade); + if (DMenu::CurrentMenu->DimAllowed()) + { + screen->Dim(fade); + V_SetBorderNeedRefresh(); + } DMenu::CurrentMenu->Drawer(); } } From 12ea8ffbe40b14208e7f1cb75e9ac5cd16d69618 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 28 Sep 2016 08:06:15 +0200 Subject: [PATCH 12/51] - removed some leftover garbage from the floating point rewrite in the floorRaiseToLowestCeiling case of DFloor. --- src/p_floor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 8d09ea2d5..62479e340 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -342,7 +342,7 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line, 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 == ceilingheight - height); + floor->m_FloorDestDist = sec->floorplane.PointToDist(spot2, ceilingheight - height); break; case DFloor::floorRaiseToHighest: From b75395aa74515092fd1bd55b4b32f98319ed900e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 28 Sep 2016 09:25:48 +0200 Subject: [PATCH 13/51] - fixed: Screen size update coordinates were copied into the wrong buffer location. --- src/gl/data/gl_vertexbuffer.cpp | 2 +- src/gl/system/gl_framebuffer.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gl/data/gl_vertexbuffer.cpp b/src/gl/data/gl_vertexbuffer.cpp index b18b367c3..4e76b51cb 100644 --- a/src/gl/data/gl_vertexbuffer.cpp +++ b/src/gl/data/gl_vertexbuffer.cpp @@ -221,7 +221,7 @@ void FFlatVertexBuffer::OutputResized(int width, int height) vbo_shadowdata[7].Set((float)width, (float)height, 0, 0, 0); Map(); - memcpy(map, &vbo_shadowdata[4], 4 * sizeof(FFlatVertex)); + memcpy(&map[4], &vbo_shadowdata[4], 4 * sizeof(FFlatVertex)); Unmap(); } diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index 08aca521f..6264352f6 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -189,7 +189,9 @@ void OpenGLFrameBuffer::Update() int clientHeight = GetClientHeight(); if (clientWidth > 0 && clientHeight > 0 && (Width != clientWidth || Height != clientHeight)) { - Resize(clientWidth, clientHeight); + // Do not call Resize here because it's only for software canvases + Pitch = Width = clientWidth; + Height = clientHeight; V_OutputResized(Width, Height); GLRenderer->mVBO->OutputResized(Width, Height); } From 676d2365e156bcb461fc0f4145b8b3476ecdf771 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 28 Sep 2016 09:49:41 +0200 Subject: [PATCH 14/51] - fixed: The ACS strings deserializer set incorrect indices in the bucket array. This only caused a problem if there were gaps in the string pool. --- src/p_acs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index fefe5cd8f..1b52f5a93 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -754,7 +754,7 @@ void ACSStringPool::ReadStrings(FSerializer &file, const char *key) unsigned bucketnum = h % NUM_BUCKETS; Pool[ii].Hash = h; Pool[ii].Next = PoolBuckets[bucketnum]; - PoolBuckets[bucketnum] = i; + PoolBuckets[bucketnum] = ii; } file.EndObject(); } From 2d5061e81f91807ebe054790719c1ce8be7fb482 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 28 Sep 2016 11:58:12 +0200 Subject: [PATCH 15/51] - fixed: DScroller did not initialize m_LastHeight in all situations. This caused a problem with the serializer because RapidJSON aborts the write of a floating point value if it is invalid. - ensure that floats are always written out. If the actual value causes an error (i.e. INF or NaN), write a 0 to guarantee proper formatting. --- src/p_scroll.cpp | 2 ++ src/serializer.cpp | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/p_scroll.cpp b/src/p_scroll.cpp index 2c7333a21..f2ece8b3d 100644 --- a/src/p_scroll.cpp +++ b/src/p_scroll.cpp @@ -259,6 +259,7 @@ DScroller::DScroller (EScroll type, double dx, double dy, m_Accel = accel; m_Parts = scrollpos; m_vdx = m_vdy = 0; + m_LastHeight = 0; if ((m_Control = control) != -1) m_LastHeight = sectors[control].CenterFloor () + sectors[control].CenterCeiling (); @@ -342,6 +343,7 @@ DScroller::DScroller (double dx, double dy, const line_t *l, m_vdx = m_vdy = 0; m_Accel = accel; m_Parts = scrollpos; + m_LastHeight = 0; if ((m_Control = control) != -1) m_LastHeight = sectors[control].CenterFloor() + sectors[control].CenterCeiling(); m_Affectee = int(l->sidedef[0] - sides); diff --git a/src/serializer.cpp b/src/serializer.cpp index 445a3b22b..47e096b7b 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -215,8 +215,14 @@ struct FWriter void Double(double k) { - if (mWriter1) mWriter1->Double(k); - else if (mWriter2) mWriter2->Double(k); + if (mWriter1) + { + if (!mWriter1->Double(k)) mWriter1->Double(0); + } + else if (mWriter2) + { + if (!mWriter2->Double(k)) mWriter2->Double(0); + } } }; From a83d1facdf15c8c869ce9bf99b4890a88e08cd88 Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Mon, 26 Sep 2016 20:31:09 -0400 Subject: [PATCH 16/51] Use GLOB_RECURSE and exclude file names with brackets, for a more complete list of PK3 source files for the IDE. # Conflicts: # CMakeLists.txt --- CMakeLists.txt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 97c44355a..922406942 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ endif() # Simplify pk3 building, add_pk3(filename srcdirectory) function( add_pk3 PK3_NAME PK3_DIR ) + # message(STATUS "Creating build rule for PK3 ${PK3_NAME} ${PK3_DIR}") # Generate target name. Just use "pk3" for main pk3 target. string( REPLACE "." "_" PK3_TARGET ${PK3_NAME} ) if( ${PK3_TARGET} STREQUAL "zdoom_pk3" ) @@ -48,8 +49,19 @@ function( add_pk3 PK3_NAME PK3_DIR ) COMMAND zipdir -udf ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} ${PK3_DIR} DEPENDS zipdir ) endif() - # Grab a list of top-level PK3 folder files, so we can conveniently see them in the IDE - file(GLOB PK3_SRCS ${PK3_DIR}/*) + file(GLOB_RECURSE PK3_SRCS ${PK3_DIR}/*) + # We're specifically avoiding some gzdoom .png files with brackets in the + # file names here, because they confuse CMake. + # This only affects the list of source files shown in the IDE. + # It does not actually remove the files from the PK3 archive. + string(REPLACE "[" confusing_bracket PK3_SRCS "${PK3_SRCS}") + string(REPLACE "]" confusing_bracket PK3_SRCS "${PK3_SRCS}") + foreach(PK3_SRC ${PK3_SRCS}) + if(${PK3_SRC} MATCHES confusing_bracket) + # message(STATUS "Ignoring PK3 file name containing brackets "${PK3_SRC}) + list(REMOVE_ITEM PK3_SRCS ${PK3_SRC}) + endif() + endforeach() # Touch the zipdir executable here so that the pk3s are forced to # rebuild each time since their dependecy has "changed." add_custom_target( ${PK3_TARGET} ALL From 3ecd20c4a163f8f2fd77fda745898492fc5de36e Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Tue, 27 Sep 2016 19:48:04 -0400 Subject: [PATCH 17/51] Enhance IDE list of PK3 source files using a more complicated approach than I had hoped for. --- CMakeLists.txt | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 922406942..541347f14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,24 @@ if(CMAKE_CROSSCOMPILING) include(${IMPORT_EXECUTABLES}) endif() +# Recursive function to place PK3 archive source files into a hierarchy of source file in the IDE +function( assort_pk3_source_folder FOLDER_NAME PK3_DIR ) + # Assort source files into folders in the IDE + file(GLOB PK3_SRCS ${PK3_DIR}/*) # Create list of all files in this folder + foreach(PK3_SRC ${PK3_SRCS}) + # If there are subfolders, recurse into them + if(IS_DIRECTORY ${PK3_SRC}) + get_filename_component(DIRNAME ${PK3_SRC} NAME) + # Exclude folder from list of source files + list(REMOVE_ITEM PK3_SRCS ${PK3_SRC}) + # Recurse deeper into the filesystem folder tree + assort_pk3_source_folder( ${FOLDER_NAME}\\${DIRNAME} ${PK3_SRC} ) + endif() + # Assign IDE group for current top-level source files + source_group(${FOLDER_NAME} FILES ${PK3_SRCS}) + endforeach() +endfunction() + # Simplify pk3 building, add_pk3(filename srcdirectory) function( add_pk3 PK3_NAME PK3_DIR ) # message(STATUS "Creating build rule for PK3 ${PK3_NAME} ${PK3_DIR}") @@ -49,25 +67,33 @@ function( add_pk3 PK3_NAME PK3_DIR ) COMMAND zipdir -udf ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} ${PK3_DIR} DEPENDS zipdir ) endif() + # Create a list of source files for this PK3, for use in the IDE + # Phase 1: Create a list of all source files for this PK3 archive, except + # for a couple of strife image file names that confuse CMake. file(GLOB_RECURSE PK3_SRCS ${PK3_DIR}/*) - # We're specifically avoiding some gzdoom .png files with brackets in the + # Exclude from the source list some gzdoom .png files with brackets in the # file names here, because they confuse CMake. # This only affects the list of source files shown in the IDE. # It does not actually remove the files from the PK3 archive. + # First replace that toxic bracket character with something we can handle string(REPLACE "[" confusing_bracket PK3_SRCS "${PK3_SRCS}") string(REPLACE "]" confusing_bracket PK3_SRCS "${PK3_SRCS}") - foreach(PK3_SRC ${PK3_SRCS}) + foreach(PK3_SRC ${PK3_SRCS}) # All source files at all levels + # Exclude those quarantined source file source file names that once had a bracket if(${PK3_SRC} MATCHES confusing_bracket) # message(STATUS "Ignoring PK3 file name containing brackets "${PK3_SRC}) list(REMOVE_ITEM PK3_SRCS ${PK3_SRC}) endif() endforeach() + # Phase 2: Create the PK3 build rule, including the source file list for the IDE # Touch the zipdir executable here so that the pk3s are forced to - # rebuild each time since their dependecy has "changed." + # rebuild each time since their dependency has "changed." add_custom_target( ${PK3_TARGET} ALL COMMAND ${CMAKE_COMMAND} -E touch $ DEPENDS ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} SOURCES ${PK3_SRCS}) + # Phase 3: Assign source files to a nice folder structure in the IDE + assort_pk3_source_folder("Source Files" ${PK3_DIR}) endfunction() # Macro for building libraries without debugging information From b400cf145499b8d0cda654938f5fc658bf929df9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 30 Sep 2016 10:50:41 +0200 Subject: [PATCH 18/51] - added an integrity check to the SNDINFO parser to detect and eliminate recursive links. Normally these would crash the sound code later. - allow recursive linking of $random definitions (as long as they do not link back, see above.) - fixed the sound precaching which did not handle $alias inside $random. Normally this went undetected but in cases where the random sound index was the same as a sound index in the current link chain this could hang the function. --- src/s_advsound.cpp | 103 +++++++++++++++++++++++++++++++++++++++++++-- src/s_sound.cpp | 15 ++++--- 2 files changed, 107 insertions(+), 11 deletions(-) diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index b073070fd..c1c19aabf 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -51,6 +51,7 @@ #include "i_system.h" #include "d_player.h" #include "serializer.h" +#include "v_text.h" // MACROS ------------------------------------------------------------------ @@ -326,6 +327,99 @@ void S_HashSounds () } } +//========================================================================== +// +// S_CheckIntegrity +// +// Scans the entire sound list and looks for recursive definitions. +//========================================================================== + +static bool S_CheckSound(sfxinfo_t *startsfx, sfxinfo_t *sfx, TArray &chain) +{ + sfxinfo_t *me = sfx; + bool success = true; + unsigned siz = chain.Size(); + + if (sfx->bPlayerReserve) + { + return true; + } + + // There is a bad link in here, but let's report it only for the sound that contains the broken definition. + // Once that sound has been disabled this one will work again. + if (chain.Find(sfx) < chain.Size()) + { + return true; + } + chain.Push(sfx); + + if (me->bRandomHeader) + { + const FRandomSoundList *list = &S_rnd[me->link]; + for (int i = 0; i < list->NumSounds; ++i) + { + auto rsfx = &S_sfx[list->Sounds[i]]; + if (rsfx == startsfx) + { + Printf(TEXTCOLOR_RED "recursive sound $random found for %s:\n", startsfx->name); + success = false; + for (unsigned i = 1; i %s\n", chain[i]->name); + } + } + else + { + success &= S_CheckSound(startsfx, rsfx, chain); + } + } + } + else if (me->link != sfxinfo_t::NO_LINK) + { + me = &S_sfx[me->link]; + if (me == startsfx) + { + Printf(TEXTCOLOR_RED "recursive sound $alias found for %s:\n", startsfx->name); + success = false; + for (unsigned i = 1; i %s\n", chain[i]->name); + } + chain.Resize(siz); + } + else + { + success &= S_CheckSound(startsfx, me, chain); + } + } + chain.Pop(); + return success; +} + +void S_CheckIntegrity() +{ + TArray chain; + TArray broken; + + broken.Resize(S_sfx.Size()); + memset(&broken[0], 0, sizeof(bool)*S_sfx.Size()); + for (unsigned i = 0; i < S_sfx.Size(); i++) + { + auto &sfx = S_sfx[i]; + broken[i] = !S_CheckSound(&sfx, &sfx, chain); + } + for (unsigned i = 0; i < S_sfx.Size(); i++) + { + if (broken[i]) + { + auto &sfx = S_sfx[i]; + Printf(TEXTCOLOR_RED "Sound %s has been disabled\n", sfx.name); + sfx.bRandomHeader = false; + sfx.link = 0; // link to the empty sound. + } + } +} + //========================================================================== // // S_PickReplacement @@ -334,13 +428,12 @@ void S_HashSounds () // is not the head of a random list, then the sound passed is returned. //========================================================================== -int S_PickReplacement (int refid) +int S_PickReplacement(int refid) { - if (S_sfx[refid].bRandomHeader) + while (S_sfx[refid].bRandomHeader) { const FRandomSoundList *list = &S_rnd[S_sfx[refid].link]; - - return list->Sounds[pr_randsound() % list->NumSounds]; + refid = list->Sounds[pr_randsound() % list->NumSounds]; } return refid; } @@ -941,6 +1034,7 @@ void S_ParseSndInfo (bool redefine) S_ShrinkPlayerSoundLists (); sfx_empty = Wads.CheckNumForName ("dsempty", ns_sounds); + S_CheckIntegrity(); } //========================================================================== @@ -961,6 +1055,7 @@ void S_AddLocalSndInfo(int lump) } S_ShrinkPlayerSoundLists (); + S_CheckIntegrity(); } //========================================================================== diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 06df0dbad..524b12175 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -522,18 +522,19 @@ void S_CacheSound (sfxinfo_t *sfx) { return; } - else if (sfx->bRandomHeader) + sfxinfo_t *orig = sfx; + while (!sfx->bRandomHeader && sfx->link != sfxinfo_t::NO_LINK) { - S_CacheRandomSound (sfx); + sfx = &S_sfx[sfx->link]; + } + if (sfx->bRandomHeader) + { + S_CacheRandomSound(sfx); } else { - while (sfx->link != sfxinfo_t::NO_LINK) - { - sfx = &S_sfx[sfx->link]; - } + S_LoadSound(sfx); sfx->bUsed = true; - S_LoadSound (sfx); } } } From e9ce699042878b58c155acfc089cda2cb9ff785b Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 1 Oct 2016 12:17:15 +0300 Subject: [PATCH 19/51] Fixed compilation with GCC or Clang --- src/s_advsound.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index c1c19aabf..0db9365c2 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -361,11 +361,11 @@ static bool S_CheckSound(sfxinfo_t *startsfx, sfxinfo_t *sfx, TArraySounds[i]]; if (rsfx == startsfx) { - Printf(TEXTCOLOR_RED "recursive sound $random found for %s:\n", startsfx->name); + Printf(TEXTCOLOR_RED "recursive sound $random found for %s:\n", startsfx->name.GetChars()); success = false; for (unsigned i = 1; i %s\n", chain[i]->name); + Printf(TEXTCOLOR_ORANGE " -> %s\n", chain[i]->name.GetChars()); } } else @@ -379,11 +379,11 @@ static bool S_CheckSound(sfxinfo_t *startsfx, sfxinfo_t *sfx, TArraylink]; if (me == startsfx) { - Printf(TEXTCOLOR_RED "recursive sound $alias found for %s:\n", startsfx->name); + Printf(TEXTCOLOR_RED "recursive sound $alias found for %s:\n", startsfx->name.GetChars()); success = false; for (unsigned i = 1; i %s\n", chain[i]->name); + Printf(TEXTCOLOR_ORANGE " -> %s\n", chain[i]->name.GetChars()); } chain.Resize(siz); } @@ -413,7 +413,7 @@ void S_CheckIntegrity() if (broken[i]) { auto &sfx = S_sfx[i]; - Printf(TEXTCOLOR_RED "Sound %s has been disabled\n", sfx.name); + Printf(TEXTCOLOR_RED "Sound %s has been disabled\n", sfx.name.GetChars()); sfx.bRandomHeader = false; sfx.link = 0; // link to the empty sound. } From 099bfed806bb3b72824ac6ae8015df99ce90b392 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sat, 1 Oct 2016 12:27:24 +0300 Subject: [PATCH 20/51] Fixed endianness issue with precaching of MUS files --- src/sound/music_mus_midiout.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index 17426a798..58b86201a 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -211,11 +211,11 @@ bool MUSSong2::CheckDone() void MUSSong2::Precache() { - TArray work(MusHeader->NumInstruments); + TArray work(LittleShort(MusHeader->NumInstruments)); const BYTE *used = (BYTE *)MusHeader + sizeof(MUSHeader) / sizeof(BYTE); int i, k; - for (i = k = 0; i < MusHeader->NumInstruments; ++i) + for (i = k = 0; i < LittleShort(MusHeader->NumInstruments); ++i) { BYTE instr = used[k++]; WORD val; From 7720359f4cf22266bb4b9bb09b1d956322197819 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 1 Oct 2016 12:08:07 +0200 Subject: [PATCH 21/51] - fixed: AActor::Masacre must restore the flag if it cannot kill the monster. --- src/p_mobj.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 400b41798..90a800fa7 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -1323,6 +1323,9 @@ bool AActor::Massacre () if (health > 0) { + auto f = flags; + auto f2 = flags2; + flags |= MF_SHOOTABLE; flags2 &= ~(MF2_DORMANT|MF2_INVULNERABLE); do @@ -1331,6 +1334,12 @@ bool AActor::Massacre () P_DamageMobj (this, NULL, NULL, TELEFRAG_DAMAGE, NAME_Massacre); } while (health != prevhealth && health > 0); //abort if the actor wasn't hurt. + if (health > 0) + { + // restore flags if this did not kill the monster. + flags = f; + flags2 = f2; + } return health <= 0; } return false; From cfa6b817b5b3af2c8590aadd133732971c146be0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 1 Oct 2016 21:34:13 +0200 Subject: [PATCH 22/51] - made bloom and tonemap settings game specific and save all related CVARs. As was pointed out: "That said, there is one minor problem - different game artstyles can constitute whether Bloom is turned on, which tonemap is used, etc. For example, when playing Doom, I like having my bloom on, but if I am going to start playing the Adventures of Square, the art style and bloom don't mix, in my opinion. For this, I have to remember to switch my bloom settings every time I switch IWad" --- src/gl/renderer/gl_postprocess.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 7ce8be0ad..03bea6d72 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -69,24 +69,24 @@ // CVARs // //========================================================================== -CVAR(Bool, gl_bloom, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); -CUSTOM_CVAR(Float, gl_bloom_amount, 1.4f, 0) +CVAR(Bool, gl_bloom, false, CVAR_ARCHIVE); +CUSTOM_CVAR(Float, gl_bloom_amount, 1.4f, CVAR_ARCHIVE) { if (self < 0.1f) self = 0.1f; } -CVAR(Float, gl_exposure_scale, 1.3f, 0) -CVAR(Float, gl_exposure_min, 0.35f, 0) -CVAR(Float, gl_exposure_base, 0.35f, 0) -CVAR(Float, gl_exposure_speed, 0.05f, 0) +CVAR(Float, gl_exposure_scale, 1.3f, CVAR_ARCHIVE) +CVAR(Float, gl_exposure_min, 0.35f, CVAR_ARCHIVE) +CVAR(Float, gl_exposure_base, 0.35f, CVAR_ARCHIVE) +CVAR(Float, gl_exposure_speed, 0.05f, CVAR_ARCHIVE) -CUSTOM_CVAR(Int, gl_tonemap, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Int, gl_tonemap, 0, CVAR_ARCHIVE) { if (self < 0 || self > 5) self = 0; } -CUSTOM_CVAR(Int, gl_bloom_kernel_size, 7, 0) +CUSTOM_CVAR(Int, gl_bloom_kernel_size, 7, CVAR_ARCHIVE) { if (self < 3 || self > 15 || self % 2 == 0) self = 7; @@ -94,9 +94,9 @@ CUSTOM_CVAR(Int, gl_bloom_kernel_size, 7, 0) 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) +CVAR(Float, gl_lens_k, -0.12f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Float, gl_lens_kcube, 0.1f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Float, gl_lens_chromatic, 1.12f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) EXTERN_CVAR(Float, vid_brightness) EXTERN_CVAR(Float, vid_contrast) From ff0b87932356181232e9912c512d98288e91596d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 Oct 2016 00:31:25 +0200 Subject: [PATCH 23/51] - added UDMF portal flags. Names are identical with Eternity for compatibility reasons. --- specs/udmf_zdoom.txt | 13 +++++++++++ src/namedef.h | 15 ++++++++++++ src/p_udmf.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index 611a667af..9662af1bb 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -214,6 +214,19 @@ Note: All fields default to false unless mentioned otherwise. damagehazard = ; // Changes damage model to Strife's delayed damage for the given sector. Default = false. floorterrain = ; // Sets the terrain for the sector's floor. Default = 'use the flat texture's terrain definition.' ceilingterrain = ; // Sets the terrain for the sector's ceiling. Default = 'use the flat texture's terrain definition.' + + portal_ceil_alpha = // translucency of ceiling portal (default is 0 (not visible)) + portal_ceil_blocksound = // ceiling portal blocks sound. + portal_ceil_disabled = // ceiling portal disabled. + portal_ceil_nopass = // ceiling portal blocks movement if true. + portal_ceil_norender = // ceiling portal not rendered. + portal_ceil_overlaytype = // defines translucency style, can either be "translucent" or "additive". Default is "translucent". + portal_floor_alpha = // translucency of floor portal (default is 0 (not visible)) + portal_floor_blocksound = // floor portal blocks sound. + portal_floor_disabled = // floor portal disabled. + portal_floor_nopass = // ceiling portal blocks movement if true. + portal_floor_norender = // ceiling portal not rendered. + portal_floor_overlaytype = // defines translucency style, can either be "translucent" or "additive". Default is "translucent". * Note about dropactors diff --git a/src/namedef.h b/src/namedef.h index c8b0d1524..36953e385 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -507,6 +507,21 @@ xx(Alphaceiling) xx(Renderstylefloor) xx(Renderstyleceiling) xx(Waterzone) +xx(portal_ceil_alpha) +xx(portal_ceil_blocksound) +xx(portal_ceil_disabled) +xx(portal_ceil_nopass) +xx(portal_ceil_norender) +xx(portal_ceil_overlaytype) +xx(portal_ceil_useglobaltex) +xx(portal_floor_alpha) +xx(portal_floor_blocksound) +xx(portal_floor_disabled) +xx(portal_floor_nopass) +xx(portal_floor_norender) +xx(portal_floor_overlaytype) +xx(portal_floor_useglobaltex) + xx(offsetx_top) xx(offsety_top) diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index c09debc51..c1a64f84b 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1568,6 +1568,60 @@ public: tagstring = CheckString(key); break; + case NAME_portal_ceil_alpha: + sec->planes[sector_t::ceiling].alpha = CheckFloat(key); + break; + + case NAME_portal_ceil_blocksound: + Flag(sec->planes[sector_t::ceiling].Flags, PLANEF_BLOCKSOUND, key); + break; + + case NAME_portal_ceil_disabled: + Flag(sec->planes[sector_t::ceiling].Flags, PLANEF_DISABLED, key); + break; + + case NAME_portal_ceil_nopass: + Flag(sec->planes[sector_t::ceiling].Flags, PLANEF_NOPASS, key); + break; + + case NAME_portal_ceil_norender: + Flag(sec->planes[sector_t::ceiling].Flags, PLANEF_NORENDER, key); + break; + + case NAME_portal_ceil_overlaytype: + if (!stricmp(CheckString(key), "translucent")) sec->planes[sector_t::ceiling].Flags &= ~PLANEF_ADDITIVE; + else if (!stricmp(CheckString(key), "additive")) sec->planes[sector_t::ceiling].Flags |= PLANEF_ADDITIVE; + break; + + case NAME_portal_floor_alpha: + sec->planes[sector_t::floor].alpha = CheckFloat(key); + break; + + case NAME_portal_floor_blocksound: + Flag(sec->planes[sector_t::floor].Flags, PLANEF_BLOCKSOUND, key); + break; + + case NAME_portal_floor_disabled: + Flag(sec->planes[sector_t::floor].Flags, PLANEF_DISABLED, key); + break; + + case NAME_portal_floor_nopass: + Flag(sec->planes[sector_t::floor].Flags, PLANEF_NOPASS, key); + break; + + case NAME_portal_floor_norender: + Flag(sec->planes[sector_t::floor].Flags, PLANEF_NORENDER, key); + break; + + case NAME_portal_floor_overlaytype: + if (!stricmp(CheckString(key), "translucent")) sec->planes[sector_t::floor].Flags &= ~PLANEF_ADDITIVE; + else if (!stricmp(CheckString(key), "additive")) sec->planes[sector_t::floor].Flags |= PLANEF_ADDITIVE; + break; + + // These two are used by Eternity for something I do not understand. + //case NAME_portal_ceil_useglobaltex: + //case NAME_portal_floor_useglobaltex: + default: break; } From 80f2f5829f50a6ae7094c6b8989d680dee59375e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 Oct 2016 00:43:05 +0200 Subject: [PATCH 24/51] - added A_SetRenderStyle function which replaces A_SetTranslucent. A_SetTranslucent had to be deprecated due to obsolete semantics of the renderstyle argument. --- src/thingdef/thingdef_codeptr.cpp | 16 ++++++++++++++++ wadsrc/static/actors/actor.txt | 1 + wadsrc/static/actors/constants.txt | 20 +++++++++++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 153c3b597..ee64df4d0 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -3322,6 +3322,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTranslucent) return 0; } +//=========================================================================== +// +// A_SetRenderStyle +// +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRenderStyle) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(alpha); + PARAM_INT_OPT(mode) { mode = 0; } + + self->Alpha = clamp(alpha, 0., 1.); + self->RenderStyle = ERenderStyle(mode); + return 0; +} + //=========================================================================== // // A_FadeIn diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 3354b91d6..fc73b02f3 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -218,6 +218,7 @@ ACTOR Actor native //: Thinker native void A_LogInt(int whattoprint); native void A_LogFloat(float whattoprint); native void A_SetTranslucent(float alpha, int style = 0); + native void A_SetRenderStyle(float alpha, int style = 0); action native A_FadeIn(float reduce = 0.1, int flags = 0); action native A_FadeOut(float reduce = 0.1, int flags = 1); //bool remove == true native void A_FadeTo(float target, float amount = 0.1, int flags = 0); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index bd6d65643..dce2488c2 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -689,4 +689,22 @@ enum VRF_NOANGLE = VRF_NOANGLESTART|VRF_NOANGLEEND, VRF_NOPITCH = VRF_NOPITCHSTART|VRF_NOPITCHEND, -}; \ No newline at end of file +}; + +enum +{ + STYLE_None, + STYLE_Normal, + STYLE_Fuzzy, + STYLE_SoulTrans, + STYLE_OptFuzzy, + STYLE_Stencil, + STYLE_Translucent, + STYLE_Add, + STYLE_Shaded, + STYLE_TranslucentStencil, + STYLE_Shadow, + STYLE_Subtract, + STYLE_AddStencil, + STYLE_AddShaded, +}; From 51ffd6d9c64eb2ae5fdf572c32087337ab1042c8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 Oct 2016 01:00:07 +0200 Subject: [PATCH 25/51] - fixed some warnings. - A_SetRenderStyle should not default to STYLE_None. --- src/p_mobj.cpp | 2 +- src/serializer.cpp | 1 - wadsrc/static/actors/actor.txt | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 90a800fa7..e39a07b2d 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3526,7 +3526,7 @@ void AActor::Tick () sector_t *sec = node->m_sector; DVector2 scrollv; - if (level.Scrolls.Size() > (sec-sectors)) + if (level.Scrolls.Size() > unsigned(sec-sectors)) { scrollv = level.Scrolls[sec - sectors]; } diff --git a/src/serializer.cpp b/src/serializer.cpp index 47e096b7b..a4714292a 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -821,7 +821,6 @@ void FSerializer::WriteObjects() for (unsigned i = 0; i < w->mDObjects.Size(); i++) { auto obj = w->mDObjects[i]; - player_t *player; BeginObject(nullptr); w->Key("classtype"); diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index fc73b02f3..713e1497f 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -218,7 +218,7 @@ ACTOR Actor native //: Thinker native void A_LogInt(int whattoprint); native void A_LogFloat(float whattoprint); native void A_SetTranslucent(float alpha, int style = 0); - native void A_SetRenderStyle(float alpha, int style = 0); + native void A_SetRenderStyle(float alpha, int style); action native A_FadeIn(float reduce = 0.1, int flags = 0); action native A_FadeOut(float reduce = 0.1, int flags = 1); //bool remove == true native void A_FadeTo(float target, float amount = 0.1, int flags = 0); From 944ae2bc09497f52ad6e81354b4f74bc6ece67d5 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Sat, 1 Oct 2016 21:47:15 -0500 Subject: [PATCH 26/51] Only generate the self==stateowner check inside action functions --- src/thingdef/thingdef.cpp | 2 +- src/thingdef/thingdef_expression.cpp | 2 +- src/zscript/vmbuilder.cpp | 3 ++- src/zscript/vmbuilder.h | 5 ++++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 635637149..32d4f1ce0 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -288,7 +288,7 @@ static void FinishThingdef() if (func == nullptr) { - VMFunctionBuilder buildit; + VMFunctionBuilder buildit(true); assert(tcall->Proto != nullptr); diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 695b12799..72a4ae30b 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3373,7 +3373,7 @@ FxExpression *FxClassMember::Resolve(FCompileContext &ctx) ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) { - if (~membervar->Flags & VARF_Native) + if (build->IsActionFunc && ~membervar->Flags & VARF_Native) { // Check if this is a user-defined variable. // As of right now, FxClassMember is only ever used with FxSelf. // This very user variable was defined in stateowner so if diff --git a/src/zscript/vmbuilder.cpp b/src/zscript/vmbuilder.cpp index eb49ffb14..8d7b5a8c1 100644 --- a/src/zscript/vmbuilder.cpp +++ b/src/zscript/vmbuilder.cpp @@ -6,7 +6,7 @@ // //========================================================================== -VMFunctionBuilder::VMFunctionBuilder() +VMFunctionBuilder::VMFunctionBuilder(bool selfcheck) { NumIntConstants = 0; NumFloatConstants = 0; @@ -14,6 +14,7 @@ VMFunctionBuilder::VMFunctionBuilder() NumStringConstants = 0; MaxParam = 0; ActiveParam = 0; + IsActionFunc = selfcheck; } //========================================================================== diff --git a/src/zscript/vmbuilder.h b/src/zscript/vmbuilder.h index 2d8721acc..ed2516c2a 100644 --- a/src/zscript/vmbuilder.h +++ b/src/zscript/vmbuilder.h @@ -23,7 +23,7 @@ public: friend class VMFunctionBuilder; }; - VMFunctionBuilder(); + VMFunctionBuilder(bool checkself = false); ~VMFunctionBuilder(); VMScriptFunction *MakeFunction(); @@ -60,6 +60,9 @@ public: // Track available registers. RegAvailability Registers[4]; + // For use by DECORATE's self/stateowner sanitizer. + bool IsActionFunc; + private: struct AddrKonst { From eb2ee339503112a0db5059c866b925cb49bdbb43 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Sat, 1 Oct 2016 22:29:57 -0500 Subject: [PATCH 27/51] FxVMFunctionCall must pass null pointers when calling an action function from a non-action function --- src/thingdef/thingdef_expression.cpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 72a4ae30b..3851d05cc 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -3948,15 +3948,16 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) //========================================================================== // -// Assumption: This call is being made to generate code inside an action -// method, so the first three address registers are all set up for such a -// function. (self, stateowner, callingstate) +// Assumption: This call is being generated inside a function whose a0 +// register is a self pointer. For action functions, a1 maps to stateowner +// and a2 maps to callingstate. (self, stateowner, callingstate) // //========================================================================== ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) { - assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3); + assert((build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= NAP) || + (!build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= 1)); int count = (ArgList ? ArgList->Size() : 0); if (count == 1) @@ -3975,8 +3976,18 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build) } if (Function->Flags & VARF_Action) { - build->Emit(OP_PARAM, 0, REGT_POINTER, 1); - build->Emit(OP_PARAM, 0, REGT_POINTER, 2); + static_assert(NAP == 3, "This code needs to be updated if NAP changes"); + if (build->IsActionFunc) + { + build->Emit(OP_PARAM, 0, REGT_POINTER, 1); + build->Emit(OP_PARAM, 0, REGT_POINTER, 2); + } + else + { + int null = build->GetConstantAddress(nullptr, ATAG_GENERIC); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, null); + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, null); + } count += 2; } // Emit code to pass explicit parameters From efc9ed2fe9685a448af32065935eb33228c011c3 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Sat, 1 Oct 2016 22:31:07 -0500 Subject: [PATCH 28/51] Fix state lookup from non-action functions (i.e. Damage functions) --- src/thingdef/thingdef_expression.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 3851d05cc..700ac94bb 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -4978,7 +4978,8 @@ static int DecoHandleRuntimeState(VMFrameStack *stack, VMValue *param, int numpa ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build) { - assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3); + assert(build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= 3 && + "FxRuntimeStateIndex is only valid inside action functions"); ExpEmit out(build, REGT_POINTER); @@ -5150,7 +5151,14 @@ int DecoFindSingleNameState(VMFrameStack *stack, VMValue *param, int numparam, V ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build) { ExpEmit dest(build, REGT_POINTER); - build->Emit(OP_PARAM, 0, REGT_POINTER, 1); // pass stateowner + if (build->IsActionFunc) + { + build->Emit(OP_PARAM, 0, REGT_POINTER, 1); // pass stateowner + } + else + { + build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self + } for (unsigned i = 0; i < names.Size(); ++i) { build->EmitParamInt(names[i]); From d7683a8c552fc38720967dedb4a89b0f0908c06f Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 2 Oct 2016 10:13:45 +0300 Subject: [PATCH 29/51] Fixed crash on early fatal error exit Process terminates correctly if zdoom.pk3 is missing --- src/dobject.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/dobject.cpp b/src/dobject.cpp index 8fba75aa6..4acb86ce4 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -330,7 +330,11 @@ DObject::~DObject () } } } - type->DestroySpecials(this); + + if (nullptr != type) + { + type->DestroySpecials(this); + } } } From a505e910321cc55f03e1fd3211ed68761bfb1bc8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 Oct 2016 13:35:25 +0200 Subject: [PATCH 30/51] - added TRNSLATE lump for defining global translations which are accessible by name. This is only the definition part, manipulation functions for ACS and DECORATE still to do. --- src/d_main.cpp | 1 + src/r_data/r_translate.cpp | 101 +++++++++++++++++++++++++-- src/r_data/r_translate.h | 6 +- src/thingdef/thingdef_properties.cpp | 7 +- 4 files changed, 104 insertions(+), 11 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 2dbf1273c..dad2b86d9 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2439,6 +2439,7 @@ void D_DoomMain (void) if (!batchrun) Printf ("ParseTeamInfo: Load team definitions.\n"); TeamLibrary.ParseTeamInfo (); + R_ParseTrnslate(); PClassActor::StaticInit (); // [GRB] Initialize player class list diff --git a/src/r_data/r_translate.cpp b/src/r_data/r_translate.cpp index c55f69016..bf9365002 100644 --- a/src/r_data/r_translate.cpp +++ b/src/r_data/r_translate.cpp @@ -609,26 +609,26 @@ void FRemapTable::AddToTranslation(const char *range) // //---------------------------------------------------------------------------- -int FRemapTable::StoreTranslation() +int FRemapTable::StoreTranslation(int slot) { unsigned int i; - for (i = 0; i < translationtables[TRANSLATION_Decorate].Size(); i++) + for (i = 0; i < translationtables[slot].Size(); i++) { - if (*this == *translationtables[TRANSLATION_Decorate][i]) + if (*this == *translationtables[slot][i]) { // A duplicate of this translation already exists - return TRANSLATION(TRANSLATION_Decorate, i); + return TRANSLATION(slot, i); } } - if (translationtables[TRANSLATION_Decorate].Size() >= MAX_DECORATE_TRANSLATIONS) + if (translationtables[slot].Size() >= MAX_DECORATE_TRANSLATIONS) { I_Error("Too many DECORATE translations"); } FRemapTable *newtrans = new FRemapTable; *newtrans = *this; - i = translationtables[TRANSLATION_Decorate].Push(newtrans); - return TRANSLATION(TRANSLATION_Decorate, i); + i = translationtables[slot].Push(newtrans); + return TRANSLATION(slot, i); } @@ -1188,3 +1188,90 @@ void R_GetPlayerTranslation (int color, const FPlayerColorSet *colorset, FPlayer R_CreatePlayerTranslation (h, s, v, colorset, skin, table, NULL, NULL); } + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- +static TMap customTranslationMap; + +int R_FindCustomTranslation(const char *name) +{ + if (name == nullptr) + { + return -1; + } + // Ice is a special case which will remain in its original slot. + if (!stricmp(name, "Ice")) + { + return TRANSLATION(TRANSLATION_Standard, 7); + } + int *t = customTranslationMap.CheckKey(FName(name, true)); + return (t != nullptr)? *t : -1; +} + +//---------------------------------------------------------------------------- +// +// +// +//---------------------------------------------------------------------------- + +void R_ParseTrnslate() +{ + customTranslationMap.Clear(); + translationtables[TRANSLATION_Custom].Clear(); + + int lump; + int lastlump = 0; + while (-1 != (lump = Wads.FindLump("TRNSLATE", &lastlump))) + { + FScanner sc(lump); + while (sc.GetToken()) + { + sc.TokenMustBe(TK_Identifier); + + FName newtrans = sc.String; + FRemapTable *base = nullptr; + if (sc.CheckToken(':')) + { + sc.MustGetAnyToken(); + if (sc.TokenType == TK_IntConst) + { + int max = 6; + if (sc.Number < 0 || sc.Number > max) + { + sc.ScriptError("Translation must be in the range [0,%d]", max); + } + base = translationtables[TRANSLATION_Standard][sc.Number]; + } + else if (sc.TokenType == TK_Identifier) + { + int tnum = R_FindCustomTranslation(sc.String); + if (tnum == -1) + { + sc.ScriptError("Base translation '%s' not found in '%s'", sc.String, newtrans.GetChars()); + } + base = translationtables[GetTranslationType(tnum)][GetTranslationIndex(tnum)]; + } + else + { + // error out. + sc.TokenMustBe(TK_Identifier); + } + } + sc.MustGetToken('='); + FRemapTable NewTranslation; + if (base != nullptr) NewTranslation = *base; + else NewTranslation.MakeIdentity(); + do + { + sc.MustGetToken(TK_StringConst); + NewTranslation.AddToTranslation(sc.String); + } while (sc.CheckToken(',')); + + int trans = NewTranslation.StoreTranslation(TRANSLATION_Custom); + customTranslationMap[newtrans] = trans; + } + } +} diff --git a/src/r_data/r_translate.h b/src/r_data/r_translate.h index a549f0759..4ca2f203f 100644 --- a/src/r_data/r_translate.h +++ b/src/r_data/r_translate.h @@ -19,6 +19,7 @@ enum TRANSLATION_Decorate, TRANSLATION_Blood, TRANSLATION_RainPillar, + TRANSLATION_Custom, NUM_TRANSLATION_TABLES }; @@ -42,7 +43,7 @@ struct FRemapTable void AddColorRange(int start, int end, int r1,int g1, int b1, int r2, int g2, int b2); void AddDesaturation(int start, int end, double r1, double g1, double b1, double r2, double g2, double b2); void AddToTranslation(const char * range); - int StoreTranslation(); + int StoreTranslation(int slot); BYTE *Remap; // For the software renderer PalEntry *Palette; // The ideal palette this maps to @@ -109,6 +110,9 @@ extern TArray BloodTranslationColors; int CreateBloodTranslation(PalEntry color); +int R_FindCustomTranslation(const char *name); +void R_ParseTrnslate(); + #endif // __R_TRANSLATE_H diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 927e3e537..d60cda823 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1100,9 +1100,10 @@ DEFINE_PROPERTY(translation, L, Actor) for(int i = 1; i < PROP_PARM_COUNT; i++) { PROP_STRING_PARM(str, i); - if (i== 1 && PROP_PARM_COUNT == 2 && !stricmp(str, "Ice")) + int tnum; + if (i== 1 && PROP_PARM_COUNT == 2 && (tnum = R_FindCustomTranslation(str)) != -1) { - defaults->Translation = TRANSLATION(TRANSLATION_Standard, 7); + defaults->Translation = tnum; return; } else @@ -1110,7 +1111,7 @@ DEFINE_PROPERTY(translation, L, Actor) CurrentTranslation.AddToTranslation(str); } } - defaults->Translation = CurrentTranslation.StoreTranslation (); + defaults->Translation = CurrentTranslation.StoreTranslation (TRANSLATION_Decorate); } } From 0bce6e39256c7054918dfe0302b83b574051e034 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 Oct 2016 14:09:45 +0200 Subject: [PATCH 31/51] - added ACS and DECORATE setter functions for named translations. --- src/actor.h | 3 +++ src/p_acs.cpp | 23 ++++++++++++++++++++++- src/p_mobj.cpp | 17 +++++++++++++++++ src/thingdef/thingdef_codeptr.cpp | 15 +++++++++++++++ wadsrc/static/actors/actor.txt | 1 + 5 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/actor.h b/src/actor.h index dbb308258..3f7c1178e 100644 --- a/src/actor.h +++ b/src/actor.h @@ -755,6 +755,9 @@ public: // What species am I? virtual FName GetSpecies(); + // set translation + void SetTranslation(const char *trname); + double GetBobOffset(double ticfrac = 0) const { if (!(flags2 & MF2_FLOATBOB)) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 1b52f5a93..0a2ccddac 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4379,10 +4379,11 @@ enum EACSFunctions ACSF_CheckClass = 200, ACSF_DamageActor, // [arookas] ACSF_SetActorFlag, + ACSF_SetTranslation, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) - ACSF_SetTeamScore, // (int team, int value) + ACSF_SetTeamScore, // (int team, int value }; int DLevelScript::SideFromID(int id, int side) @@ -6002,6 +6003,26 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) return count; } + case ACSF_SetTranslation: + { + int tid = args[0]; + const char *trname = FBehavior::StaticLookupString(args[1]); + if (tid == 0) + { + if (activator != nullptr) + activator->SetTranslation(trname); + } + else + { + FActorIterator it(tid); + while ((actor = it.Next()) != nullptr) + { + actor->SetTranslation(trname); + } + } + return 1; + } + default: break; } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index e39a07b2d..496f52e86 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -6525,6 +6525,23 @@ int AActor::ApplyDamageFactor(FName damagetype, int damage) const } +void AActor::SetTranslation(const char *trname) +{ + if (*trname == 0) + { + // an empty string resets to the default + Translation = GetDefault()->Translation; + return; + } + + int tnum = R_FindCustomTranslation(trname); + if (tnum >= 0) + { + Translation = tnum; + } + // silently ignore if the name does not exist, this would create some insane message spam otherwise. +} + //---------------------------------------------------------------------------- // // DropItem handling diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index ee64df4d0..3b4e6203e 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -7412,3 +7412,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetVisibleRotation) ACTION_RETURN_BOOL(true); } + +//========================================================================== +// +// +// +//========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTranslation) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_STRING(trname); + + self->SetTranslation(trname); + return 0; +} diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 713e1497f..c82be96cd 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -344,6 +344,7 @@ ACTOR Actor native //: Thinker action native bool A_SetSpriteAngle(float angle = 0, int ptr = AAPTR_DEFAULT); action native bool A_SetSpriteRotation(float angle = 0, int ptr = AAPTR_DEFAULT); action native bool A_SetVisibleRotation(float anglestart = 0, float angleend = 0, float pitchstart = 0, float pitchend = 0, int flags = 0, int ptr = AAPTR_DEFAULT); + native void A_SetTranslation(string transname); native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0); native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0); From 865863ab6fb2d8cd464bc6637955eaf11bb41b57 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 Oct 2016 14:37:26 +0200 Subject: [PATCH 32/51] - fixed: AFastProjectile did not work properly for perfectly vertically moving missiles. Like AActor::Tick it needs to ensure that a tiny bit of lateral movement is present so that collision detection and the Effect() function work as intended. --- src/g_shared/a_fastprojectile.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index c1253f966..ec736bfea 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -54,6 +54,12 @@ void AFastProjectile::Tick () // Handle movement if (!Vel.isZero() || (Z() != floorz)) { + // force some lateral movement so that collision detection works as intended. + if ((flags & MF_MISSILE) && Vel.X == 0 && Vel.Y == 0 && !IsZeroDamage()) + { + Vel.X = MinVel; + } + frac = Vel / count; changexy = frac.X != 0 || frac.Y != 0; int ripcount = count / 8; From 3418710a383d18323d0e9aa37e171a1ca0b15db9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 Oct 2016 14:38:48 +0200 Subject: [PATCH 33/51] - be a bit more thorough and also call Effect() on vertically moving missiles with zero damage. --- src/g_shared/a_fastprojectile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_shared/a_fastprojectile.cpp b/src/g_shared/a_fastprojectile.cpp index ec736bfea..82349c1a7 100644 --- a/src/g_shared/a_fastprojectile.cpp +++ b/src/g_shared/a_fastprojectile.cpp @@ -130,7 +130,7 @@ void AFastProjectile::Tick () P_ExplodeMissile (this, NULL, NULL); return; } - if (changexy && ripcount <= 0) + if (!frac.isZero() && ripcount <= 0) { ripcount = count >> 3; Effect(); From 37d61167ea80e3d7985e984ff9259b5dc7108831 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 Oct 2016 18:50:37 +0200 Subject: [PATCH 34/51] - hotfix for a RapidJSON bug: If the Writer tries to process an INF or NaN value, it aborts and leaves the writer in a broken state, unable to recover. Changed so that it writes a 0 value so that the resulting JSON at least parses correctly. --- src/rapidjson/writer.h | 42 +++++++++++++++++++++++++----------------- src/serializer.cpp | 4 ++-- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/rapidjson/writer.h b/src/rapidjson/writer.h index c5a3b98a9..369e7e6ff 100644 --- a/src/rapidjson/writer.h +++ b/src/rapidjson/writer.h @@ -322,22 +322,30 @@ protected: bool WriteDouble(double d) { if (internal::Double(d).IsNanOrInf()) { - if (!(writeFlags & kWriteNanAndInfFlag)) - return false; - if (internal::Double(d).IsNan()) { - PutReserve(*os_, 3); - PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); - return true; - } - if (internal::Double(d).Sign()) { - PutReserve(*os_, 9); - PutUnsafe(*os_, '-'); - } - else - PutReserve(*os_, 8); - PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); - PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); - return true; + bool ret = true; + if (!(writeFlags & kWriteNanAndInfFlag)) + { + // if we abort here, the writer is left in a broken state, unable to recover, so better write a 0 in addition to returning an error. + ret = false; + d = 0; + } + else + { + if (internal::Double(d).IsNan()) { + PutReserve(*os_, 3); + PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); + return true; + } + if (internal::Double(d).Sign()) { + PutReserve(*os_, 9); + PutUnsafe(*os_, '-'); + } + else + PutReserve(*os_, 8); + PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); + PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); + return true; + } } char buffer[25]; @@ -345,7 +353,7 @@ protected: PutReserve(*os_, static_cast(end - buffer)); for (char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast(*p)); - return true; + return ret; } bool WriteString(const Ch* str, SizeType length) { diff --git a/src/serializer.cpp b/src/serializer.cpp index a4714292a..7861701c0 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -217,11 +217,11 @@ struct FWriter { if (mWriter1) { - if (!mWriter1->Double(k)) mWriter1->Double(0); + mWriter1->Double(k); } else if (mWriter2) { - if (!mWriter2->Double(k)) mWriter2->Double(0); + mWriter2->Double(k); } } From e84a7de390f1b9de1d178d18f76f1a534bb3afee Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 2 Oct 2016 18:56:04 +0200 Subject: [PATCH 35/51] - variable was in the wrong scope. --- src/rapidjson/writer.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rapidjson/writer.h b/src/rapidjson/writer.h index 369e7e6ff..a8eeab66d 100644 --- a/src/rapidjson/writer.h +++ b/src/rapidjson/writer.h @@ -321,8 +321,8 @@ protected: } bool WriteDouble(double d) { - if (internal::Double(d).IsNanOrInf()) { - bool ret = true; + bool ret = true; + if (internal::Double(d).IsNanOrInf()) { if (!(writeFlags & kWriteNanAndInfFlag)) { // if we abort here, the writer is left in a broken state, unable to recover, so better write a 0 in addition to returning an error. From 1620ff58c8f5f3f63bf3a71ff9f1320164545d1d Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Sun, 2 Oct 2016 12:24:48 -0500 Subject: [PATCH 36/51] Added INTCVAR to DrawNumber. - Allows retrieval and displaying of an int/bool user/server cvar. --- src/g_shared/sbarinfo_commands.cpp | 53 +++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index b7827f6bd..13c98d833 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -1021,7 +1021,7 @@ class CommandDrawNumber : public CommandDrawString usePrefix(false), interpolationSpeed(0), drawValue(0), length(3), lowValue(-1), lowTranslation(CR_UNTRANSLATED), highValue(-1), highTranslation(CR_UNTRANSLATED), value(CONSTANT), - inventoryItem(NULL) + inventoryItem(NULL), cvarName(nullptr) { } @@ -1166,6 +1166,37 @@ class CommandDrawNumber : public CommandDrawString if(parenthesized) sc.MustGetToken(')'); } + else if (sc.Compare("intcvar")) + { + bool parenthesized = sc.CheckToken('('); + + value = INTCVAR; + + if (!parenthesized || !sc.CheckToken(TK_StringConst)) + sc.MustGetToken(TK_Identifier); + + cvarName = sc.String; + + // We have a name, but make sure it exists. If not, send notification so modders + // are aware of the situation. + FBaseCVar *CVar = FindCVar(cvarName, nullptr); + + if (CVar != nullptr) + { + ECVarType cvartype = CVar->GetRealType(); + + if (!(cvartype == CVAR_Bool || cvartype == CVAR_Int)) + { + sc.ScriptMessage("CVar '%s' is not an int or bool", cvarName); + } + } + else + { + sc.ScriptMessage("CVar '%s' does not exist", cvarName); + } + + if (parenthesized) sc.MustGetToken(')'); + } } if(value == INVENTORY) { @@ -1444,6 +1475,24 @@ class CommandDrawNumber : public CommandDrawString num++; } break; + case INTCVAR: + { + FBaseCVar *CVar = GetCVar(statusBar->CPlayer->mo, cvarName); + if (CVar != nullptr) + { + ECVarType cvartype = CVar->GetRealType(); + + if (cvartype == CVAR_Bool || cvartype == CVAR_Int) + { + num = CVar->GetGenericRep(CVAR_Int).Int; + break; + } + } + + // Fallback in case of bad cvar/type. Unset can remove a cvar at will. + num = 0; + break; + } default: break; } if(interpolationSpeed != 0 && (!hudChanged || level.time == 1)) @@ -1522,6 +1571,7 @@ class CommandDrawNumber : public CommandDrawString ACCURACY, STAMINA, KEYS, + INTCVAR, CONSTANT }; @@ -1544,6 +1594,7 @@ class CommandDrawNumber : public CommandDrawString PClassActor *inventoryItem; FString prefixPadding; + FString cvarName; friend class CommandDrawInventoryBar; }; From 671646be26ef8d6cdcef12f198a92d297f7b215f Mon Sep 17 00:00:00 2001 From: "N.E.C" Date: Sun, 2 Oct 2016 13:05:26 -0700 Subject: [PATCH 37/51] Fix errors encountered when compiling for v140_xp target --- src/CMakeLists.txt | 45 +++++++++++++++++++++++++++++------------- src/win32/i_xinput.cpp | 6 ++++++ 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ab5f137ef..03299bb0a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,6 +9,8 @@ endif() include( CheckCXXSourceCompiles ) include( CheckFunctionExists ) include( CheckCXXCompilerFlag ) +include( CheckIncludeFile ) +include( CheckIncludeFiles ) include( CheckLibraryExists ) include( FindPkgConfig ) @@ -118,7 +120,13 @@ if( WIN32 ) PATHS ENV DXSDK_DIR PATH_SUFFIXES Include ) if( NOT D3D_INCLUDE_DIR ) - message( SEND_ERROR "Could not find DirectX 9 header files" ) + # Modern versions of the Windows SDK include d3d9.h. Unfortunately, + # CMake cannot find this file via find_path, so we check for it using + # CHECK_INCLUDE_FILE. + CHECK_INCLUDE_FILE( d3d9.h D3D9_H_FOUND ) + if ( NOT D3D9_H_FOUND ) + message( SEND_ERROR "Could not find DirectX 9 header files" ) + endif() else() include_directories( ${D3D_INCLUDE_DIR} ) endif() @@ -127,35 +135,41 @@ if( WIN32 ) PATHS ENV DXSDK_DIR PATH_SUFFIXES Include ) if( NOT XINPUT_INCLUDE_DIR ) - message( WARNING "Could not find xinput.h. XInput will be disabled." ) - add_definitions( -DNO_XINPUT ) + # Modern versions of the Windows SDK include xinput.h. Unfortunately, + # CMake cannot find this file via find_path, so we check for it using + # CHECK_INCLUDE_FILES. windows.h must be included before xinput.h. + CHECK_INCLUDE_FILES( "windows.h;xinput.h" XINPUT_H_FOUND ) + if( NOT XINPUT_H_FOUND ) + message( WARNING "Could not find xinput.h. XInput will be disabled." ) + add_definitions( -DNO_XINPUT ) + endif() else() include_directories( ${XINPUT_INCLUDE_DIR} ) endif() - find_library( DX_dxguid_LIBRARY dxguid - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Lib Lib/${XBITS} ) find_library( DX_dinput8_LIBRARY dinput8 PATHS ENV DXSDK_DIR PATH_SUFFIXES Lib Lib/${XBITS} ) + find_library( DX_dxguid_LIBRARY dxguid + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Lib Lib/${XBITS} ) - set( DX_LIBS_FOUND YES ) - if( NOT DX_dxguid_LIBRARY ) - set( DX_LIBS_FOUND NO ) - endif() + # Modern versions of the Windows SDK include dinput8.lib. Unfortunately, + # CMake cannot find these libraries via find_library. if( NOT DX_dinput8_LIBRARY ) - set( DX_LIBS_FOUND NO ) + # If we got this far, assume dinput8.lib is in the system library path. + set( DX_dinput8_LIBRARY dinput8 ) endif() - if( NOT DX_LIBS_FOUND ) - message( FATAL_ERROR "Could not find DirectX 9 libraries" ) + # Modern versions of the Windows SDK do NOT include dxguid.lib. Its contents + # were moved to dinput8.lib. + if( NOT DX_dxguid_LIBRARY ) + message( STATUS "Could not find dxguid.lib. Build may fail on old Windows SDKs.") endif() set( ZDOOM_LIBS wsock32 winmm - "${DX_dxguid_LIBRARY}" "${DX_dinput8_LIBRARY}" ole32 user32 @@ -166,6 +180,9 @@ if( WIN32 ) setupapi oleaut32 DelayImp ) + if( DX_dxguid_LIBRARY ) + list( APPEND ZDOOM_LIBS "${DX_dxguid_LIBRARY}" ) + endif() else() if( APPLE ) set( FMOD_SEARCH_PATHS "/Developer/FMOD Programmers API Mac/api" ) diff --git a/src/win32/i_xinput.cpp b/src/win32/i_xinput.cpp index b00b4c510..1180f9f32 100644 --- a/src/win32/i_xinput.cpp +++ b/src/win32/i_xinput.cpp @@ -27,6 +27,12 @@ // MACROS ------------------------------------------------------------------ +// This macro is defined by newer versions of xinput.h. In case we are +// compiling with an older version, define it here. +#ifndef XUSER_MAX_COUNT +#define XUSER_MAX_COUNT 4 +#endif + // TYPES ------------------------------------------------------------------- typedef DWORD (WINAPI *XInputGetStateType)(DWORD index, XINPUT_STATE *state); From 960d4d6755db3089a8d270c009a7549a9761e76b Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Thu, 22 Sep 2016 20:44:56 -0400 Subject: [PATCH 38/51] Create TopBottom3D mode and begin sketching RowInterleaved3D mode. --- src/CMakeLists.txt | 1 + src/gl/stereo3d/gl_interleaved3d.cpp | 71 ++++++++++++++++++++++++++++ src/gl/stereo3d/gl_interleaved3d.h | 58 +++++++++++++++++++++++ src/gl/stereo3d/gl_sidebyside3d.cpp | 38 +++++++++++++++ src/gl/stereo3d/gl_sidebyside3d.h | 8 ++++ src/gl/stereo3d/gl_stereo_cvars.cpp | 7 +++ wadsrc/static/language.enu | 2 + wadsrc/static/menudef.zz | 2 + 8 files changed, 187 insertions(+) create mode 100644 src/gl/stereo3d/gl_interleaved3d.cpp create mode 100644 src/gl/stereo3d/gl_interleaved3d.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 73dba07c4..e768e945f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1116,6 +1116,7 @@ set( FASTMATH_SOURCES gl/stereo3d/gl_anaglyph.cpp gl/stereo3d/gl_quadstereo.cpp gl/stereo3d/gl_sidebyside3d.cpp + gl/stereo3d/gl_interleaved3d.cpp gl/dynlights/gl_dynlight.cpp gl/dynlights/gl_glow.cpp gl/dynlights/gl_dynlight1.cpp diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp new file mode 100644 index 000000000..c811e0d21 --- /dev/null +++ b/src/gl/stereo3d/gl_interleaved3d.cpp @@ -0,0 +1,71 @@ +/* +** gl_interleaved3d.cpp +** Interleaved image stereoscopic 3D modes for GZDoom +** +**--------------------------------------------------------------------------- +** Copyright 2016 Christopher Bruns +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "gl_interleaved3d.h" +#include "gl/renderer/gl_renderer.h" +#include "gl/renderer/gl_renderbuffers.h" + +namespace s3d { + +/* static */ +const RowInterleaved3D& RowInterleaved3D::getInstance(float ipd) +{ + static RowInterleaved3D instance(ipd); + return instance; +} + +void RowInterleaved3D::Present() const +{ + GLRenderer->mBuffers->BindOutputFB(); + GLRenderer->ClearBorders(); + + // Compute screen regions to use for left and right eye views + int topHeight = GLRenderer->mOutputLetterbox.height / 2; + int bottomHeight = GLRenderer->mOutputLetterbox.height - topHeight; + GL_IRECT topHalfScreen = GLRenderer->mOutputLetterbox; + topHalfScreen.height = topHeight; + GL_IRECT bottomHalfScreen = GLRenderer->mOutputLetterbox; + bottomHalfScreen.height = bottomHeight; + bottomHalfScreen.top += topHeight; + + GLRenderer->mBuffers->BindEyeTexture(0, 0); + GLRenderer->DrawPresentTexture(topHalfScreen, true); + + GLRenderer->mBuffers->BindEyeTexture(1, 0); + GLRenderer->DrawPresentTexture(bottomHalfScreen, true); +} + + +} /* namespace s3d */ diff --git a/src/gl/stereo3d/gl_interleaved3d.h b/src/gl/stereo3d/gl_interleaved3d.h new file mode 100644 index 000000000..1f22fa356 --- /dev/null +++ b/src/gl/stereo3d/gl_interleaved3d.h @@ -0,0 +1,58 @@ +/* +** gl_interleaved3d.h +** Interleaved stereoscopic 3D modes for GZDoom +** +**--------------------------------------------------------------------------- +** Copyright 2016 Christopher Bruns +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#ifndef GL_INTERLEAVED3D_H_ +#define GL_INTERLEAVED3D_H_ + +#include "gl_stereo3d.h" +#include "gl_stereo_leftright.h" +#include "gl_sidebyside3d.h" +#include "gl/system/gl_system.h" +#include "gl/renderer/gl_renderstate.h" + +namespace s3d { + +class RowInterleaved3D : public TopBottom3D +{ +public: + static const RowInterleaved3D& getInstance(float ipd); + RowInterleaved3D(double ipdMeters) : TopBottom3D(ipdMeters) {} + void Present() const override; +}; + +} /* namespace s3d */ + + +#endif /* GL_INTERLEAVED3D_H_ */ diff --git a/src/gl/stereo3d/gl_sidebyside3d.cpp b/src/gl/stereo3d/gl_sidebyside3d.cpp index c6463d2c8..d2b0cafdd 100644 --- a/src/gl/stereo3d/gl_sidebyside3d.cpp +++ b/src/gl/stereo3d/gl_sidebyside3d.cpp @@ -108,4 +108,42 @@ void SideBySideFull::AdjustPlayerSprites() const /* override */ gl_RenderState.ApplyMatrices(); } +/* static */ +const TopBottom3D& TopBottom3D::getInstance(float ipd) +{ + static TopBottom3D instance(ipd); + return instance; +} + +void TopBottom3D::Present() const +{ + GLRenderer->mBuffers->BindOutputFB(); + GLRenderer->ClearBorders(); + + // Compute screen regions to use for left and right eye views + int topHeight = GLRenderer->mOutputLetterbox.height / 2; + int bottomHeight = GLRenderer->mOutputLetterbox.height - topHeight; + GL_IRECT topHalfScreen = GLRenderer->mOutputLetterbox; + topHalfScreen.height = topHeight; + GL_IRECT bottomHalfScreen = GLRenderer->mOutputLetterbox; + bottomHalfScreen.height = bottomHeight; + bottomHalfScreen.top += topHeight; + + GLRenderer->mBuffers->BindEyeTexture(0, 0); + GLRenderer->DrawPresentTexture(topHalfScreen, true); + + GLRenderer->mBuffers->BindEyeTexture(1, 0); + GLRenderer->DrawPresentTexture(bottomHalfScreen, true); +} + +// AdjustViewports() is called from within FLGRenderer::SetOutputViewport(...) +void TopBottom3D::AdjustViewports() const +{ + // Change size of renderbuffer, and align to screen + GLRenderer->mSceneViewport.height /= 2; + GLRenderer->mSceneViewport.top /= 2; + GLRenderer->mScreenViewport.height /= 2; + GLRenderer->mScreenViewport.top /= 2; +} + } /* namespace s3d */ diff --git a/src/gl/stereo3d/gl_sidebyside3d.h b/src/gl/stereo3d/gl_sidebyside3d.h index 374f255c5..c98f748a0 100644 --- a/src/gl/stereo3d/gl_sidebyside3d.h +++ b/src/gl/stereo3d/gl_sidebyside3d.h @@ -88,6 +88,14 @@ private: SBSFRightEyePose rightEye; }; +class TopBottom3D : public SideBySideSquished +{ +public: + static const TopBottom3D& getInstance(float ipd); + TopBottom3D(double ipdMeters) : SideBySideSquished(ipdMeters) {} + void Present() const override; + virtual void AdjustViewports() const override; +}; } /* namespace s3d */ diff --git a/src/gl/stereo3d/gl_stereo_cvars.cpp b/src/gl/stereo3d/gl_stereo_cvars.cpp index c09a7a974..16296393d 100644 --- a/src/gl/stereo3d/gl_stereo_cvars.cpp +++ b/src/gl/stereo3d/gl_stereo_cvars.cpp @@ -30,6 +30,7 @@ #include "gl/stereo3d/gl_anaglyph.h" #include "gl/stereo3d/gl_quadstereo.h" #include "gl/stereo3d/gl_sidebyside3d.h" +#include "gl/stereo3d/gl_interleaved3d.h" #include "gl/system/gl_cvars.h" // Set up 3D-specific console variables: @@ -100,6 +101,12 @@ const Stereo3DMode& Stereo3DMode::getCurrentMode() setCurrentMode(AmberBlue::getInstance(vr_ipd)); break; // TODO: 10: HTC Vive/OpenVR + case 11: + setCurrentMode(TopBottom3D::getInstance(vr_ipd)); + break; + case 12: + setCurrentMode(RowInterleaved3D::getInstance(vr_ipd)); + break; case 0: default: setCurrentMode(MonoView::getInstance()); diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 50526a75b..813d6b8f6 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2703,6 +2703,8 @@ OPTVAL_LEFTEYE = "Left Eye"; OPTVAL_RIGHTEYE = "Right Eye"; OPTVAL_SBSFULL = "Side-by-side Full"; OPTVAL_SBSNARROW = "Side-by-side Narrow"; +OPTVAL_TOPBOTTOM = "Top/Bottom"; +OPTVAL_ROWINTERLEAVED = "Row Interleaved"; OPTVAL_QUADBUFFERED = "Quad-buffered"; OPTVAL_UNCHARTED2 = "Uncharted 2"; OPTVAL_HEJLDAWSON = "Hejl Dawson"; diff --git a/wadsrc/static/menudef.zz b/wadsrc/static/menudef.zz index 1ab4f1a6d..6f96ea286 100644 --- a/wadsrc/static/menudef.zz +++ b/wadsrc/static/menudef.zz @@ -169,6 +169,8 @@ OptionValue VRMode 9, "$OPTVAL_AMBERBLUE" 3, "$OPTVAL_SBSFULL" 4, "$OPTVAL_SBSNARROW" + 11, "$OPTVAL_TOPBOTTOM" + 12, "$OPTVAL_ROWINTERLEAVED" 5, "$OPTVAL_LEFTEYE" 6, "$OPTVAL_RIGHTEYE" 7, "$OPTVAL_QUADBUFFERED" From 79046580d586df604aa30be88c0d3efc1ccc7e2d Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Tue, 27 Sep 2016 19:49:24 -0400 Subject: [PATCH 39/51] Partial implementation of row interlaced mode. --- src/gl/renderer/gl_renderbuffers.cpp | 20 ++++++++++++++++++++ src/gl/renderer/gl_renderbuffers.h | 2 ++ src/gl/stereo3d/gl_interleaved3d.cpp | 13 +++++-------- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index b2471e4b9..31fc36832 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -576,6 +576,26 @@ void FGLRenderBuffers::BlitToEyeTexture(int eye) glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } +void FGLRenderBuffers::BlitFromEyeTexture(int eye, GL_IRECT* box) +{ + glBindFramebuffer(GL_READ_FRAMEBUFFER, mEyeFBs[eye]); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mOutputFB); + if (box == nullptr) + box = &GLRenderer->mOutputLetterbox; + glBlitFramebuffer(0, 0, mWidth, mHeight, + box->left, box->top, box->width + box->left, box->height + box->top, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + + if ((gl.flags & RFL_INVALIDATE_BUFFER) != 0) + { + GLenum attachments[2] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_STENCIL_ATTACHMENT }; + glInvalidateFramebuffer(GL_READ_FRAMEBUFFER, 2, attachments); + } + + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); +} + void FGLRenderBuffers::BindEyeTexture(int eye, int texunit) { CreateEyeBuffers(eye); diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 4477718f4..043cb8852 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -2,6 +2,7 @@ #define __GL_RENDERBUFFERS_H #include "gl/shaders/gl_shader.h" +#include "gl/renderer/gl_renderer.h" class FGLBloomTextureLevel { @@ -42,6 +43,7 @@ public: void BindOutputFB(); void BlitToEyeTexture(int eye); + void BlitFromEyeTexture(int eye, GL_IRECT* box); void BindEyeTexture(int eye, int texunit); void BindEyeFB(int eye, bool readBuffer = false); diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp index c811e0d21..085efae51 100644 --- a/src/gl/stereo3d/gl_interleaved3d.cpp +++ b/src/gl/stereo3d/gl_interleaved3d.cpp @@ -53,18 +53,15 @@ void RowInterleaved3D::Present() const // Compute screen regions to use for left and right eye views int topHeight = GLRenderer->mOutputLetterbox.height / 2; - int bottomHeight = GLRenderer->mOutputLetterbox.height - topHeight; GL_IRECT topHalfScreen = GLRenderer->mOutputLetterbox; topHalfScreen.height = topHeight; + topHalfScreen.top = topHeight; GL_IRECT bottomHalfScreen = GLRenderer->mOutputLetterbox; - bottomHalfScreen.height = bottomHeight; - bottomHalfScreen.top += topHeight; + bottomHalfScreen.height = topHeight; + bottomHalfScreen.top = 0; - GLRenderer->mBuffers->BindEyeTexture(0, 0); - GLRenderer->DrawPresentTexture(topHalfScreen, true); - - GLRenderer->mBuffers->BindEyeTexture(1, 0); - GLRenderer->DrawPresentTexture(bottomHalfScreen, true); + GLRenderer->mBuffers->BlitFromEyeTexture(0, &topHalfScreen); + GLRenderer->mBuffers->BlitFromEyeTexture(1, &bottomHalfScreen); } From 460b6537096062c904eed7c016871757e11957e5 Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Sun, 2 Oct 2016 12:24:37 -0400 Subject: [PATCH 40/51] Row interlaced 3d might be working, at least in fullscreen 1920x1080 mode. --- src/CMakeLists.txt | 1 + src/gl/renderer/gl_renderer.cpp | 4 ++ src/gl/renderer/gl_renderer.h | 2 + src/gl/shaders/gl_present3dRowshader.cpp | 60 +++++++++++++++++++++ src/gl/shaders/gl_present3dRowshader.h | 51 ++++++++++++++++++ src/gl/stereo3d/gl_interleaved3d.cpp | 49 ++++++++++++++++- src/gl/stereo3d/gl_interleaved3d.h | 4 +- src/gl/stereo3d/gl_sidebyside3d.cpp | 3 +- wadsrc/static/shaders/glsl/present_row3d.fp | 36 +++++++++++++ 9 files changed, 206 insertions(+), 4 deletions(-) create mode 100644 src/gl/shaders/gl_present3dRowshader.cpp create mode 100644 src/gl/shaders/gl_present3dRowshader.h create mode 100644 wadsrc/static/shaders/glsl/present_row3d.fp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e768e945f..7307e6eec 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1125,6 +1125,7 @@ set( FASTMATH_SOURCES gl/shaders/gl_texshader.cpp gl/shaders/gl_shaderprogram.cpp gl/shaders/gl_presentshader.cpp + gl/shaders/gl_present3dRowshader.cpp gl/shaders/gl_bloomshader.cpp gl/shaders/gl_blurshader.cpp gl/shaders/gl_colormapshader.cpp diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 42b4a8e1b..fbfa51440 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -57,6 +57,7 @@ #include "gl/shaders/gl_colormapshader.h" #include "gl/shaders/gl_lensshader.h" #include "gl/shaders/gl_presentshader.h" +#include "gl/shaders/gl_present3dRowshader.h" #include "gl/stereo3d/gl_stereo3d.h" #include "gl/textures/gl_texture.h" #include "gl/textures/gl_translate.h" @@ -103,6 +104,7 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) mTonemapPalette = nullptr; mBuffers = nullptr; mPresentShader = nullptr; + mPresent3dRowShader = nullptr; mBloomExtractShader = nullptr; mBloomCombineShader = nullptr; mExposureExtractShader = nullptr; @@ -132,6 +134,7 @@ void FGLRenderer::Initialize(int width, int height) mTonemapPalette = nullptr; mLensShader = new FLensShader(); mPresentShader = new FPresentShader(); + mPresent3dRowShader = new FPresent3DRowShader(); m2DDrawer = new F2DDrawer; // needed for the core profile, because someone decided it was a good idea to remove the default VAO. @@ -184,6 +187,7 @@ FGLRenderer::~FGLRenderer() } if (mBuffers) delete mBuffers; if (mPresentShader) delete mPresentShader; + if (mPresent3dRowShader) delete mPresent3dRowShader; if (mBloomExtractShader) delete mBloomExtractShader; if (mBloomCombineShader) delete mBloomCombineShader; if (mExposureExtractShader) delete mExposureExtractShader; diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 71c52474a..460b5685a 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -29,6 +29,7 @@ class FTonemapShader; class FColormapShader; class FLensShader; class FPresentShader; +class FPresent3DRowShader; class F2DDrawer; class FHardwareTexture; @@ -104,6 +105,7 @@ public: FHardwareTexture *mTonemapPalette; FLensShader *mLensShader; FPresentShader *mPresentShader; + FPresent3DRowShader *mPresent3dRowShader; FTexture *gllight; FTexture *glpart2; diff --git a/src/gl/shaders/gl_present3dRowshader.cpp b/src/gl/shaders/gl_present3dRowshader.cpp new file mode 100644 index 000000000..607e4ede6 --- /dev/null +++ b/src/gl/shaders/gl_present3dRowshader.cpp @@ -0,0 +1,60 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2016 Christopher Bruns +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_3dRowshader.cpp +** Copy rendered texture to back buffer, possibly with gamma correction +** while interleaving rows from two independent viewpoint textures, +** representing the left-eye and right-eye views. +** +*/ + +#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_present3dRowshader.h" + +void FPresent3DRowShader::Bind() +{ + if (!mShader) + { + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquadscale.vp", "", 330); + mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/present_row3d.fp", "", 330); + mShader.SetFragDataLocation(0, "FragColor"); + mShader.Link("shaders/glsl/presentRow3d"); + mShader.SetAttribLocation(0, "PositionInProjection"); + mShader.SetAttribLocation(1, "UV"); + LeftEyeTexture.Init(mShader, "LeftEyeTexture"); + RightEyeTexture.Init(mShader, "RightEyeTexture"); + InvGamma.Init(mShader, "InvGamma"); + Contrast.Init(mShader, "Contrast"); + Brightness.Init(mShader, "Brightness"); + Scale.Init(mShader, "UVScale"); + VerticalPixelOffset.Init(mShader, "VerticalPixelOffset"); + } + mShader.Bind(); +} diff --git a/src/gl/shaders/gl_present3dRowshader.h b/src/gl/shaders/gl_present3dRowshader.h new file mode 100644 index 000000000..8e3bd772d --- /dev/null +++ b/src/gl/shaders/gl_present3dRowshader.h @@ -0,0 +1,51 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2015 Christopher Bruns +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// +/* +** gl_present3dRowshader.h +** Final composition and present shader for row-interleaved stereoscopic 3D mode +** +*/ + +#ifndef GL_PRESENT3DROWSHADER_H_ +#define GL_PRESENT3DROWSHADER_H_ + +#include "gl_shaderprogram.h" + +class FPresent3DRowShader +{ +public: + void Bind(); + + FBufferedUniformSampler LeftEyeTexture; + FBufferedUniformSampler RightEyeTexture; + FBufferedUniform1f InvGamma; + FBufferedUniform1f Contrast; + FBufferedUniform1f Brightness; + FBufferedUniform2f Scale; + FBufferedUniform1i VerticalPixelOffset; + +private: + FShaderProgram mShader; +}; + +// GL_PRESENT3DROWSHADER_H_ +#endif \ No newline at end of file diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp index 085efae51..28b9c373e 100644 --- a/src/gl/stereo3d/gl_interleaved3d.cpp +++ b/src/gl/stereo3d/gl_interleaved3d.cpp @@ -36,6 +36,12 @@ #include "gl_interleaved3d.h" #include "gl/renderer/gl_renderer.h" #include "gl/renderer/gl_renderbuffers.h" +#include "gl/renderer/gl_renderer.h" +#include "gl/system/gl_framebuffer.h" +#include "gl/shaders/gl_present3dRowshader.h" + +EXTERN_CVAR(Float, vid_brightness) +EXTERN_CVAR(Float, vid_contrast) namespace s3d { @@ -46,6 +52,10 @@ const RowInterleaved3D& RowInterleaved3D::getInstance(float ipd) return instance; } +RowInterleaved3D::RowInterleaved3D(double ipdMeters) + : TopBottom3D(ipdMeters) +{} + void RowInterleaved3D::Present() const { GLRenderer->mBuffers->BindOutputFB(); @@ -60,8 +70,43 @@ void RowInterleaved3D::Present() const bottomHalfScreen.height = topHeight; bottomHalfScreen.top = 0; - GLRenderer->mBuffers->BlitFromEyeTexture(0, &topHalfScreen); - GLRenderer->mBuffers->BlitFromEyeTexture(1, &bottomHalfScreen); + // Bind each eye texture, for composition in the shader + GLRenderer->mBuffers->BindEyeTexture(0, 0); + GLRenderer->mBuffers->BindEyeTexture(1, 1); + + glActiveTexture(GL_TEXTURE0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glActiveTexture(GL_TEXTURE1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + const GL_IRECT& box = GLRenderer->mOutputLetterbox; + glViewport(box.left, box.top, box.width, box.height); + + bool applyGamma = true; + + GLRenderer->mPresent3dRowShader->Bind(); + GLRenderer->mPresent3dRowShader->LeftEyeTexture.Set(0); + GLRenderer->mPresent3dRowShader->RightEyeTexture.Set(1); + if (!applyGamma || GLRenderer->framebuffer->IsHWGammaActive()) + { + GLRenderer->mPresent3dRowShader->InvGamma.Set(1.0f); + GLRenderer->mPresent3dRowShader->Contrast.Set(1.0f); + GLRenderer->mPresent3dRowShader->Brightness.Set(0.0f); + } + else + { + GLRenderer->mPresent3dRowShader->InvGamma.Set(1.0f / clamp(Gamma, 0.1f, 4.f)); + GLRenderer->mPresent3dRowShader->Contrast.Set(clamp(vid_contrast, 0.1f, 3.f)); + GLRenderer->mPresent3dRowShader->Brightness.Set(clamp(vid_brightness, -0.8f, 0.8f)); + } + GLRenderer->mPresent3dRowShader->Scale.Set( + GLRenderer->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(), + GLRenderer->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight()); + GLRenderer->mPresent3dRowShader->VerticalPixelOffset.Set(0); // fixme: vary with window location + GLRenderer->RenderScreenQuad(); } diff --git a/src/gl/stereo3d/gl_interleaved3d.h b/src/gl/stereo3d/gl_interleaved3d.h index 1f22fa356..30aef7d5a 100644 --- a/src/gl/stereo3d/gl_interleaved3d.h +++ b/src/gl/stereo3d/gl_interleaved3d.h @@ -42,13 +42,15 @@ #include "gl/system/gl_system.h" #include "gl/renderer/gl_renderstate.h" +class FPresent3DRowShader; + namespace s3d { class RowInterleaved3D : public TopBottom3D { public: static const RowInterleaved3D& getInstance(float ipd); - RowInterleaved3D(double ipdMeters) : TopBottom3D(ipdMeters) {} + RowInterleaved3D(double ipdMeters); void Present() const override; }; diff --git a/src/gl/stereo3d/gl_sidebyside3d.cpp b/src/gl/stereo3d/gl_sidebyside3d.cpp index d2b0cafdd..ecb3ec1cc 100644 --- a/src/gl/stereo3d/gl_sidebyside3d.cpp +++ b/src/gl/stereo3d/gl_sidebyside3d.cpp @@ -125,9 +125,10 @@ void TopBottom3D::Present() const int bottomHeight = GLRenderer->mOutputLetterbox.height - topHeight; GL_IRECT topHalfScreen = GLRenderer->mOutputLetterbox; topHalfScreen.height = topHeight; + topHalfScreen.top = topHeight; GL_IRECT bottomHalfScreen = GLRenderer->mOutputLetterbox; bottomHalfScreen.height = bottomHeight; - bottomHalfScreen.top += topHeight; + bottomHalfScreen.top = 0; GLRenderer->mBuffers->BindEyeTexture(0, 0); GLRenderer->DrawPresentTexture(topHalfScreen, true); diff --git a/wadsrc/static/shaders/glsl/present_row3d.fp b/wadsrc/static/shaders/glsl/present_row3d.fp new file mode 100644 index 000000000..18bd3cd11 --- /dev/null +++ b/wadsrc/static/shaders/glsl/present_row3d.fp @@ -0,0 +1,36 @@ + +in vec2 TexCoord; +out vec4 FragColor; + +uniform sampler2D LeftEyeTexture; +uniform sampler2D RightEyeTexture; +uniform float InvGamma; +uniform float Contrast; +uniform float Brightness; +uniform int VerticalPixelOffset; // top-of-window might not be top-of-screen + +vec4 ApplyGamma(vec4 c) +{ + vec3 val = c.rgb * Contrast - (Contrast - 1.0) * 0.5; + val += Brightness * 0.5; + val = pow(max(val, vec3(0.0)), vec3(InvGamma)); + return vec4(val, c.a); +} + +void main() +{ + // NOTE we assume here that the full screen height is the sum of the left + // and right eye view heights + int screenHeightInPixels = textureSize(LeftEyeTexture, 0).y + textureSize(RightEyeTexture, 0).y; + int thisVerticalPixel = int(TexCoord.y * screenHeightInPixels + 0.5); + bool isLeftEye = (thisVerticalPixel + VerticalPixelOffset) % 2 == 0; + vec4 inputColor; + if (isLeftEye) { + inputColor = texture(LeftEyeTexture, TexCoord); + } + else { + // inputColor = vec4(0, 1, 0, 1); + inputColor = texture(RightEyeTexture, TexCoord); + } + FragColor = ApplyGamma(inputColor); +} From fcbf9342d69a04619042df12c88e857e7d41ee4e Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Sun, 2 Oct 2016 13:11:07 -0400 Subject: [PATCH 41/51] Compute row location using gl_FragCoord. --- src/gl/shaders/gl_present3dRowshader.cpp | 1 + src/gl/shaders/gl_present3dRowshader.h | 1 + src/gl/stereo3d/gl_interleaved3d.cpp | 13 +++++-------- wadsrc/static/shaders/glsl/present_row3d.fp | 6 ++---- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/gl/shaders/gl_present3dRowshader.cpp b/src/gl/shaders/gl_present3dRowshader.cpp index 607e4ede6..931278aaa 100644 --- a/src/gl/shaders/gl_present3dRowshader.cpp +++ b/src/gl/shaders/gl_present3dRowshader.cpp @@ -54,6 +54,7 @@ void FPresent3DRowShader::Bind() Contrast.Init(mShader, "Contrast"); Brightness.Init(mShader, "Brightness"); Scale.Init(mShader, "UVScale"); + WindowHeight.Init(mShader, "WindowHeight"); VerticalPixelOffset.Init(mShader, "VerticalPixelOffset"); } mShader.Bind(); diff --git a/src/gl/shaders/gl_present3dRowshader.h b/src/gl/shaders/gl_present3dRowshader.h index 8e3bd772d..b7f0d87b2 100644 --- a/src/gl/shaders/gl_present3dRowshader.h +++ b/src/gl/shaders/gl_present3dRowshader.h @@ -41,6 +41,7 @@ public: FBufferedUniform1f Contrast; FBufferedUniform1f Brightness; FBufferedUniform2f Scale; + FBufferedUniform1i WindowHeight; FBufferedUniform1i VerticalPixelOffset; private: diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp index 28b9c373e..5e0281ee6 100644 --- a/src/gl/stereo3d/gl_interleaved3d.cpp +++ b/src/gl/stereo3d/gl_interleaved3d.cpp @@ -61,14 +61,6 @@ void RowInterleaved3D::Present() const GLRenderer->mBuffers->BindOutputFB(); GLRenderer->ClearBorders(); - // Compute screen regions to use for left and right eye views - int topHeight = GLRenderer->mOutputLetterbox.height / 2; - GL_IRECT topHalfScreen = GLRenderer->mOutputLetterbox; - topHalfScreen.height = topHeight; - topHalfScreen.top = topHeight; - GL_IRECT bottomHalfScreen = GLRenderer->mOutputLetterbox; - bottomHalfScreen.height = topHeight; - bottomHalfScreen.top = 0; // Bind each eye texture, for composition in the shader GLRenderer->mBuffers->BindEyeTexture(0, 0); @@ -90,6 +82,7 @@ void RowInterleaved3D::Present() const GLRenderer->mPresent3dRowShader->Bind(); GLRenderer->mPresent3dRowShader->LeftEyeTexture.Set(0); GLRenderer->mPresent3dRowShader->RightEyeTexture.Set(1); + if (!applyGamma || GLRenderer->framebuffer->IsHWGammaActive()) { GLRenderer->mPresent3dRowShader->InvGamma.Set(1.0f); @@ -105,7 +98,11 @@ void RowInterleaved3D::Present() const GLRenderer->mPresent3dRowShader->Scale.Set( GLRenderer->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(), GLRenderer->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight()); + + GLRenderer->mPresent3dRowShader->WindowHeight.Set(0); + GLRenderer->mPresent3dRowShader->VerticalPixelOffset.Set(0); // fixme: vary with window location + GLRenderer->RenderScreenQuad(); } diff --git a/wadsrc/static/shaders/glsl/present_row3d.fp b/wadsrc/static/shaders/glsl/present_row3d.fp index 18bd3cd11..73a01539b 100644 --- a/wadsrc/static/shaders/glsl/present_row3d.fp +++ b/wadsrc/static/shaders/glsl/present_row3d.fp @@ -7,6 +7,7 @@ uniform sampler2D RightEyeTexture; uniform float InvGamma; uniform float Contrast; uniform float Brightness; +uniform int WindowHeight; uniform int VerticalPixelOffset; // top-of-window might not be top-of-screen vec4 ApplyGamma(vec4 c) @@ -19,10 +20,7 @@ vec4 ApplyGamma(vec4 c) void main() { - // NOTE we assume here that the full screen height is the sum of the left - // and right eye view heights - int screenHeightInPixels = textureSize(LeftEyeTexture, 0).y + textureSize(RightEyeTexture, 0).y; - int thisVerticalPixel = int(TexCoord.y * screenHeightInPixels + 0.5); + int thisVerticalPixel = int(gl_FragCoord.y); bool isLeftEye = (thisVerticalPixel + VerticalPixelOffset) % 2 == 0; vec4 inputColor; if (isLeftEye) { From 576619504e63e0385e2d7500da8859980327e058 Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Sun, 2 Oct 2016 13:12:22 -0400 Subject: [PATCH 42/51] Remove unused WindowHeight uniform. --- src/gl/shaders/gl_present3dRowshader.cpp | 1 - src/gl/shaders/gl_present3dRowshader.h | 1 - src/gl/stereo3d/gl_interleaved3d.cpp | 2 -- 3 files changed, 4 deletions(-) diff --git a/src/gl/shaders/gl_present3dRowshader.cpp b/src/gl/shaders/gl_present3dRowshader.cpp index 931278aaa..607e4ede6 100644 --- a/src/gl/shaders/gl_present3dRowshader.cpp +++ b/src/gl/shaders/gl_present3dRowshader.cpp @@ -54,7 +54,6 @@ void FPresent3DRowShader::Bind() Contrast.Init(mShader, "Contrast"); Brightness.Init(mShader, "Brightness"); Scale.Init(mShader, "UVScale"); - WindowHeight.Init(mShader, "WindowHeight"); VerticalPixelOffset.Init(mShader, "VerticalPixelOffset"); } mShader.Bind(); diff --git a/src/gl/shaders/gl_present3dRowshader.h b/src/gl/shaders/gl_present3dRowshader.h index b7f0d87b2..8e3bd772d 100644 --- a/src/gl/shaders/gl_present3dRowshader.h +++ b/src/gl/shaders/gl_present3dRowshader.h @@ -41,7 +41,6 @@ public: FBufferedUniform1f Contrast; FBufferedUniform1f Brightness; FBufferedUniform2f Scale; - FBufferedUniform1i WindowHeight; FBufferedUniform1i VerticalPixelOffset; private: diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp index 5e0281ee6..fd7a6c4c6 100644 --- a/src/gl/stereo3d/gl_interleaved3d.cpp +++ b/src/gl/stereo3d/gl_interleaved3d.cpp @@ -99,8 +99,6 @@ void RowInterleaved3D::Present() const GLRenderer->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(), GLRenderer->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight()); - GLRenderer->mPresent3dRowShader->WindowHeight.Set(0); - GLRenderer->mPresent3dRowShader->VerticalPixelOffset.Set(0); // fixme: vary with window location GLRenderer->RenderScreenQuad(); From 0240cdef18ec31b62fc53ed946d49fc775b4cacb Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Sun, 2 Oct 2016 13:49:57 -0400 Subject: [PATCH 43/51] Modulate row interleaved stereo 3d offset with window height parity, because gl_FragCoord.y approaches zero at the bottom, not the top of the window. --- src/gl/stereo3d/gl_interleaved3d.cpp | 5 ++++- wadsrc/static/shaders/glsl/present_row3d.fp | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp index fd7a6c4c6..225f52819 100644 --- a/src/gl/stereo3d/gl_interleaved3d.cpp +++ b/src/gl/stereo3d/gl_interleaved3d.cpp @@ -99,7 +99,10 @@ void RowInterleaved3D::Present() const GLRenderer->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(), GLRenderer->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight()); - GLRenderer->mPresent3dRowShader->VerticalPixelOffset.Set(0); // fixme: vary with window location + GLRenderer->mPresent3dRowShader->VerticalPixelOffset.Set( + 0 // fixme: vary with window location + + box.height % 2 // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset + ); GLRenderer->RenderScreenQuad(); } diff --git a/wadsrc/static/shaders/glsl/present_row3d.fp b/wadsrc/static/shaders/glsl/present_row3d.fp index 73a01539b..8ae72d1e0 100644 --- a/wadsrc/static/shaders/glsl/present_row3d.fp +++ b/wadsrc/static/shaders/glsl/present_row3d.fp @@ -7,7 +7,6 @@ uniform sampler2D RightEyeTexture; uniform float InvGamma; uniform float Contrast; uniform float Brightness; -uniform int WindowHeight; uniform int VerticalPixelOffset; // top-of-window might not be top-of-screen vec4 ApplyGamma(vec4 c) @@ -20,8 +19,10 @@ vec4 ApplyGamma(vec4 c) void main() { - int thisVerticalPixel = int(gl_FragCoord.y); - bool isLeftEye = (thisVerticalPixel + VerticalPixelOffset) % 2 == 0; + int thisVerticalPixel = int(gl_FragCoord.y + 1.0); // Bottom row is typically the right eye, when WindowHeight is even + bool isLeftEye = (thisVerticalPixel // because we want to alternate eye view on each row + + VerticalPixelOffset // because the window might not be aligned to the screen + ) % 2 == 0; vec4 inputColor; if (isLeftEye) { inputColor = texture(LeftEyeTexture, TexCoord); From 63b28a1d80a7d055616978de8d9f8c1c77f8dc64 Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Sun, 2 Oct 2016 16:04:52 -0400 Subject: [PATCH 44/51] Retain stereoscopic parity after dragging window in row interleaved 3D mode. --- src/gl/stereo3d/gl_interleaved3d.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp index 225f52819..329dec953 100644 --- a/src/gl/stereo3d/gl_interleaved3d.cpp +++ b/src/gl/stereo3d/gl_interleaved3d.cpp @@ -42,6 +42,8 @@ EXTERN_CVAR(Float, vid_brightness) EXTERN_CVAR(Float, vid_contrast) +EXTERN_CVAR(Bool, fullscreen) +EXTERN_CVAR(Int, win_y) // pixel position of top of display window namespace s3d { @@ -99,8 +101,16 @@ void RowInterleaved3D::Present() const GLRenderer->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(), GLRenderer->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight()); + // Compute absolute offset from top of screen to top of current display window + // because we need screen-relative, not window-relative, scan line parity + int windowVOffset = 0; + if (! fullscreen) { + I_SaveWindowedPos(); // update win_y CVAR + windowVOffset = win_y; + } + GLRenderer->mPresent3dRowShader->VerticalPixelOffset.Set( - 0 // fixme: vary with window location + windowVOffset // fixme: vary with window location + box.height % 2 // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset ); From 5391216756165e0f1e66db3b141c4b4c0c9849fb Mon Sep 17 00:00:00 2001 From: Christopher Bruns Date: Sun, 2 Oct 2016 16:27:43 -0400 Subject: [PATCH 45/51] Delete unused new BlitFromEyeTexture() method I ended up not using. --- src/gl/renderer/gl_renderbuffers.cpp | 20 -------------------- src/gl/renderer/gl_renderbuffers.h | 1 - 2 files changed, 21 deletions(-) diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index 31fc36832..b2471e4b9 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -576,26 +576,6 @@ void FGLRenderBuffers::BlitToEyeTexture(int eye) glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } -void FGLRenderBuffers::BlitFromEyeTexture(int eye, GL_IRECT* box) -{ - glBindFramebuffer(GL_READ_FRAMEBUFFER, mEyeFBs[eye]); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mOutputFB); - if (box == nullptr) - box = &GLRenderer->mOutputLetterbox; - glBlitFramebuffer(0, 0, mWidth, mHeight, - box->left, box->top, box->width + box->left, box->height + box->top, - GL_COLOR_BUFFER_BIT, GL_NEAREST); - - if ((gl.flags & RFL_INVALIDATE_BUFFER) != 0) - { - GLenum attachments[2] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_STENCIL_ATTACHMENT }; - glInvalidateFramebuffer(GL_READ_FRAMEBUFFER, 2, attachments); - } - - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -} - void FGLRenderBuffers::BindEyeTexture(int eye, int texunit) { CreateEyeBuffers(eye); diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 043cb8852..5fe05f5ac 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -43,7 +43,6 @@ public: void BindOutputFB(); void BlitToEyeTexture(int eye); - void BlitFromEyeTexture(int eye, GL_IRECT* box); void BindEyeTexture(int eye, int texunit); void BindEyeFB(int eye, bool readBuffer = false); From c68aa2b24168d6baf373edffc7f1f5b2eb18b2ca Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 25 Sep 2016 12:25:01 +0300 Subject: [PATCH 46/51] Added FXAA post-processing Implementation of Fast Approximate Anti-Aliasing is based on nVidia sample: https://github.com/NVIDIAGameWorks/GraphicsSamples/tree/master/samples/es3-kepler/FXAA --- docs/licenses/fxaa.txt | 33 ++ src/CMakeLists.txt | 1 + src/gl/renderer/gl_postprocess.cpp | 54 +++ src/gl/renderer/gl_renderer.cpp | 7 + src/gl/renderer/gl_renderer.h | 5 + src/gl/scene/gl_scene.cpp | 1 + src/gl/shaders/gl_fxaashader.cpp | 99 +++++ src/gl/shaders/gl_fxaashader.h | 66 ++++ wadsrc/static/language.enu | 7 +- wadsrc/static/menudef.zz | 10 + wadsrc/static/shaders/glsl/fxaa.fp | 615 +++++++++++++++++++++++++++++ 11 files changed, 897 insertions(+), 1 deletion(-) create mode 100644 docs/licenses/fxaa.txt create mode 100644 src/gl/shaders/gl_fxaashader.cpp create mode 100644 src/gl/shaders/gl_fxaashader.h create mode 100644 wadsrc/static/shaders/glsl/fxaa.fp diff --git a/docs/licenses/fxaa.txt b/docs/licenses/fxaa.txt new file mode 100644 index 000000000..fbd143c1d --- /dev/null +++ b/docs/licenses/fxaa.txt @@ -0,0 +1,33 @@ +//---------------------------------------------------------------------------------- +// File: es3-kepler\FXAA/FXAA3_11.h +// SDK Version: v3.00 +// Email: gameworks@nvidia.com +// Site: http://developer.nvidia.com/ +// +// Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of NVIDIA CORPORATION nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 COPYRIGHT OWNER OR +// CONTRIBUTORS 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. +// +//---------------------------------------------------------------------------------- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7307e6eec..19e5c9a0c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1131,6 +1131,7 @@ set( FASTMATH_SOURCES gl/shaders/gl_colormapshader.cpp gl/shaders/gl_tonemapshader.cpp gl/shaders/gl_lensshader.cpp + gl/shaders/gl_fxaashader.cpp gl/system/gl_interface.cpp gl/system/gl_framebuffer.cpp gl/system/gl_debug.cpp diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 03bea6d72..52339e587 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -60,6 +60,7 @@ #include "gl/shaders/gl_tonemapshader.h" #include "gl/shaders/gl_colormapshader.h" #include "gl/shaders/gl_lensshader.h" +#include "gl/shaders/gl_fxaashader.h" #include "gl/shaders/gl_presentshader.h" #include "gl/renderer/gl_2ddrawer.h" #include "gl/stereo3d/gl_stereo3d.h" @@ -98,6 +99,14 @@ CVAR(Float, gl_lens_k, -0.12f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Float, gl_lens_kcube, 0.1f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Float, gl_lens_chromatic, 1.12f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Int, gl_fxaa, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < 0 || self >= FFXAAShader::Count) + { + self = 0; + } +} + EXTERN_CVAR(Float, vid_brightness) EXTERN_CVAR(Float, vid_contrast) @@ -447,6 +456,51 @@ void FGLRenderer::LensDistortScene() FGLDebug::PopGroup(); } +//----------------------------------------------------------------------------- +// +// Apply FXAA and place the result in the HUD/2D texture +// +//----------------------------------------------------------------------------- + +void FGLRenderer::ApplyFXAA() +{ + if (0 == gl_fxaa) + { + return; + } + + FGLDebug::PushGroup("ApplyFXAA"); + + const GLfloat rpcRes[2] = + { + 1.0f / mBuffers->GetWidth(), + 1.0f / mBuffers->GetHeight() + }; + + FGLPostProcessState savedState; + + mBuffers->BindNextFB(); + mBuffers->BindCurrentTexture(0); + mFXAALumaShader->Bind(); + mFXAALumaShader->InputTexture.Set(0); + RenderScreenQuad(); + mBuffers->NextTexture(); + + 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); + mFXAAShader->Bind(); + mFXAAShader->InputTexture.Set(0); + mFXAAShader->ReciprocalResolution.Set(rpcRes); + RenderScreenQuad(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + mBuffers->NextTexture(); + + FGLDebug::PopGroup(); +} + //----------------------------------------------------------------------------- // // Copies the rendered screen to its final destination diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index fbfa51440..be1b96f15 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -56,6 +56,7 @@ #include "gl/shaders/gl_tonemapshader.h" #include "gl/shaders/gl_colormapshader.h" #include "gl/shaders/gl_lensshader.h" +#include "gl/shaders/gl_fxaashader.h" #include "gl/shaders/gl_presentshader.h" #include "gl/shaders/gl_present3dRowshader.h" #include "gl/stereo3d/gl_stereo3d.h" @@ -115,6 +116,8 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) mTonemapPalette = nullptr; mColormapShader = nullptr; mLensShader = nullptr; + mFXAAShader = nullptr; + mFXAALumaShader = nullptr; } void gl_LoadModels(); @@ -133,6 +136,8 @@ void FGLRenderer::Initialize(int width, int height) mColormapShader = new FColormapShader(); mTonemapPalette = nullptr; mLensShader = new FLensShader(); + mFXAAShader = new FFXAAShader; + mFXAALumaShader = new FFXAALumaShader; mPresentShader = new FPresentShader(); mPresent3dRowShader = new FPresent3DRowShader(); m2DDrawer = new F2DDrawer; @@ -198,6 +203,8 @@ FGLRenderer::~FGLRenderer() if (mTonemapPalette) delete mTonemapPalette; if (mColormapShader) delete mColormapShader; if (mLensShader) delete mLensShader; + delete mFXAAShader; + delete mFXAALumaShader; } //========================================================================== diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 460b5685a..65e31c52f 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -28,6 +28,8 @@ class FBlurShader; class FTonemapShader; class FColormapShader; class FLensShader; +class FFXAALumaShader; +class FFXAAShader; class FPresentShader; class FPresent3DRowShader; class F2DDrawer; @@ -104,6 +106,8 @@ public: FColormapShader *mColormapShader; FHardwareTexture *mTonemapPalette; FLensShader *mLensShader; + FFXAALumaShader *mFXAALumaShader; + FFXAAShader *mFXAAShader; FPresentShader *mPresentShader; FPresent3DRowShader *mPresent3dRowShader; @@ -180,6 +184,7 @@ public: void BindTonemapPalette(int texunit); void ClearTonemapPalette(); void LensDistortScene(); + void ApplyFXAA(); void CopyToBackbuffer(const GL_IRECT *bounds, bool applyGamma); void DrawPresentTexture(const GL_IRECT &box, bool applyGamma); void Flush(); diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 0c76b4bb1..4b7bc762f 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -832,6 +832,7 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo TonemapScene(); ColormapScene(); LensDistortScene(); + ApplyFXAA(); // This should be done after postprocessing, not before. mBuffers->BindCurrentFB(); diff --git a/src/gl/shaders/gl_fxaashader.cpp b/src/gl/shaders/gl_fxaashader.cpp new file mode 100644 index 000000000..277c7fbb3 --- /dev/null +++ b/src/gl/shaders/gl_fxaashader.cpp @@ -0,0 +1,99 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2016 Alexey Lysiuk +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +// +// Fast approXimate Anti-Aliasing (FXAA) post-processing +// + +#include "gl/system/gl_system.h" +#include "gl/shaders/gl_fxaashader.h" + +EXTERN_CVAR(Int, gl_fxaa) + +void FFXAALumaShader::Bind() +{ + if (!mShader) + { + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/fxaa.fp", "#define FXAA_LUMA_PASS\n", 330); + mShader.SetFragDataLocation(0, "FragColor"); + mShader.Link("shaders/glsl/fxaa"); + mShader.SetAttribLocation(0, "PositionInProjection"); + InputTexture.Init(mShader, "InputTexture"); + } + + mShader.Bind(); +} + +static int GetMaxVersion() +{ + return gl.glslversion >= 4.f ? 400 : 330; +} + +static FString GetDefines() +{ + int quality; + + switch (gl_fxaa) + { + default: + case FFXAAShader::Low: quality = 10; break; + case FFXAAShader::Medium: quality = 12; break; + case FFXAAShader::High: quality = 29; break; + case FFXAAShader::Extreme: quality = 39; break; + } + + const int gatherAlpha = GetMaxVersion() >= 400 ? 1 : 0; + + // TODO: enable FXAA_GATHER4_ALPHA on OpenGL earlier than 4.0 + // when GL_ARB_gpu_shader5/GL_NV_gpu_shader5 extensions are supported + + FString result; + result.Format( + "#define FXAA_QUALITY__PRESET %i\n" + "#define FXAA_GATHER4_ALPHA %i\n", + quality, gatherAlpha); + + return result; +} + +void FFXAAShader::Bind() +{ + assert(gl_fxaa > 0 && gl_fxaa < Count); + FShaderProgram &shader = mShaders[gl_fxaa]; + + if (!shader) + { + const FString defines = GetDefines(); + const int maxVersion = GetMaxVersion(); + + shader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + shader.Compile(FShaderProgram::Fragment, "shaders/glsl/fxaa.fp", defines, maxVersion); + shader.SetFragDataLocation(0, "FragColor"); + shader.Link("shaders/glsl/fxaa"); + shader.SetAttribLocation(0, "PositionInProjection"); + InputTexture.Init(shader, "InputTexture"); + ReciprocalResolution.Init(shader, "ReciprocalResolution"); + } + + shader.Bind(); +} diff --git a/src/gl/shaders/gl_fxaashader.h b/src/gl/shaders/gl_fxaashader.h new file mode 100644 index 000000000..5ebcd232e --- /dev/null +++ b/src/gl/shaders/gl_fxaashader.h @@ -0,0 +1,66 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2016 Alexey Lysiuk +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +// +// Fast approXimate Anti-Aliasing (FXAA) post-processing +// + +#ifndef __GL_FXAASHADER_H__ +#define __GL_FXAASHADER_H__ + +#include "gl_shaderprogram.h" + +class FFXAALumaShader +{ +public: + void Bind(); + + FBufferedUniform1i InputTexture; + +private: + FShaderProgram mShader; +}; + + +class FFXAAShader +{ +public: + enum Quality + { + None, + Low, + Medium, + High, + Extreme, + Count + }; + + void Bind(); + + FBufferedUniform1i InputTexture; + FBufferedUniform2f ReciprocalResolution; + +private: + FShaderProgram mShaders[Count]; +}; + +#endif // __GL_FXAASHADER_H__ diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 813d6b8f6..224764a87 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2633,6 +2633,7 @@ GLPREFMNU_MULTISAMPLE = "Multisample"; GLPREFMNU_TONEMAP = "Tonemap Mode"; GLPREFMNU_BLOOM = "Bloom effect"; GLPREFMNU_LENS = "Lens distortion effect"; +GLPREFMNU_FXAA = "FXAA Quality"; // Option Values OPTVAL_SMART = "Smart"; @@ -2709,4 +2710,8 @@ OPTVAL_QUADBUFFERED = "Quad-buffered"; OPTVAL_UNCHARTED2 = "Uncharted 2"; OPTVAL_HEJLDAWSON = "Hejl Dawson"; OPTVAL_REINHARD = "Reinhard"; -OPTVAL_PALETTE = "Palette"; \ No newline at end of file +OPTVAL_PALETTE = "Palette"; +OPTVAL_LOW = "Low"; +OPTVAL_MEDIUM = "Medium"; +OPTVAL_HIGH = "High"; +OPTVAL_EXTREME = "Extreme"; diff --git a/wadsrc/static/menudef.zz b/wadsrc/static/menudef.zz index 6f96ea286..7e798a039 100644 --- a/wadsrc/static/menudef.zz +++ b/wadsrc/static/menudef.zz @@ -42,6 +42,15 @@ OptionValue "TonemapModes" 5, "$OPTVAL_PALETTE" } +OptionValue "FXAAQuality" +{ + 0, "$OPTVAL_OFF" + 1, "$OPTVAL_LOW" + 2, "$OPTVAL_MEDIUM" + 3, "$OPTVAL_HIGH" + 4, "$OPTVAL_EXTREME" +} + OptionValue "TextureFormats" { 0, "$OPTVAL_RGBA8" @@ -228,4 +237,5 @@ OptionMenu "GLPrefOptions" Option "$GLPREFMNU_TONEMAP", gl_tonemap, "TonemapModes" Option "$GLPREFMNU_BLOOM", gl_bloom, "OnOff" Option "$GLPREFMNU_LENS", gl_lens, "OnOff" + Option "$GLPREFMNU_FXAA", gl_fxaa, "FXAAQuality" } diff --git a/wadsrc/static/shaders/glsl/fxaa.fp b/wadsrc/static/shaders/glsl/fxaa.fp new file mode 100644 index 000000000..7fcdf8c81 --- /dev/null +++ b/wadsrc/static/shaders/glsl/fxaa.fp @@ -0,0 +1,615 @@ +//---------------------------------------------------------------------------------- +// File: es3-kepler\FXAA/FXAA3_11.h +// SDK Version: v3.00 +// Email: gameworks@nvidia.com +// Site: http://developer.nvidia.com/ +// +// Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of NVIDIA CORPORATION nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 COPYRIGHT OWNER OR +// CONTRIBUTORS 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. +// +//---------------------------------------------------------------------------------- + +in vec2 TexCoord; +out vec4 FragColor; + +uniform sampler2D InputTexture; + +#ifdef FXAA_LUMA_PASS + +void main() +{ + vec3 tex = texture(InputTexture, TexCoord).rgb; + vec3 luma = vec3(0.299, 0.587, 0.114); + FragColor = vec4(tex, dot(tex, luma)); +} + +#else // FXAA itself + +//============================================================================ +// NVIDIA FXAA 3.11 by TIMOTHY LOTTES +//============================================================================ + +#define FXAA_DISCARD 1 + +#define FXAA_GREEN_AS_LUMA 0 + +#define FxaaBool bool +#define FxaaDiscard discard +#define FxaaFloat float +#define FxaaFloat2 vec2 +#define FxaaFloat3 vec3 +#define FxaaFloat4 vec4 +#define FxaaHalf float +#define FxaaHalf2 vec2 +#define FxaaHalf3 vec3 +#define FxaaHalf4 vec4 +#define FxaaInt2 ivec2 +#define FxaaSat(x) clamp(x, 0.0, 1.0) +#define FxaaTex sampler2D + +#define FxaaTexTop(t, p) textureLod(t, p, 0.0) +#define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o) + +#if (FXAA_GATHER4_ALPHA == 1) + #define FxaaTexAlpha4(t, p) textureGather(t, p, 3) + #define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3) + #define FxaaTexGreen4(t, p) textureGather(t, p, 1) + #define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1) +#endif + +#if (FXAA_GREEN_AS_LUMA == 0) + FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.w; } +#else + FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.y; } +#endif + +#if (FXAA_QUALITY__PRESET == 10) + #define FXAA_QUALITY__PS 3 + #define FXAA_QUALITY__P0 1.5 + #define FXAA_QUALITY__P1 3.0 + #define FXAA_QUALITY__P2 12.0 +#elif (FXAA_QUALITY__PRESET == 11) + #define FXAA_QUALITY__PS 4 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 3.0 + #define FXAA_QUALITY__P3 12.0 +#elif (FXAA_QUALITY__PRESET == 12) + #define FXAA_QUALITY__PS 5 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 4.0 + #define FXAA_QUALITY__P4 12.0 +#elif (FXAA_QUALITY__PRESET == 13) + #define FXAA_QUALITY__PS 6 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 4.0 + #define FXAA_QUALITY__P5 12.0 +#elif (FXAA_QUALITY__PRESET == 14) + #define FXAA_QUALITY__PS 7 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 4.0 + #define FXAA_QUALITY__P6 12.0 +#elif (FXAA_QUALITY__PRESET == 15) + #define FXAA_QUALITY__PS 8 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 4.0 + #define FXAA_QUALITY__P7 12.0 +#elif (FXAA_QUALITY__PRESET == 20) + #define FXAA_QUALITY__PS 3 + #define FXAA_QUALITY__P0 1.5 + #define FXAA_QUALITY__P1 2.0 + #define FXAA_QUALITY__P2 8.0 +#elif (FXAA_QUALITY__PRESET == 21) + #define FXAA_QUALITY__PS 4 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 8.0 +#elif (FXAA_QUALITY__PRESET == 22) + #define FXAA_QUALITY__PS 5 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 8.0 +#elif (FXAA_QUALITY__PRESET == 23) + #define FXAA_QUALITY__PS 6 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 8.0 +#elif (FXAA_QUALITY__PRESET == 24) + #define FXAA_QUALITY__PS 7 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 3.0 + #define FXAA_QUALITY__P6 8.0 +#elif (FXAA_QUALITY__PRESET == 25) + #define FXAA_QUALITY__PS 8 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 4.0 + #define FXAA_QUALITY__P7 8.0 +#elif (FXAA_QUALITY__PRESET == 26) + #define FXAA_QUALITY__PS 9 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 4.0 + #define FXAA_QUALITY__P8 8.0 +#elif (FXAA_QUALITY__PRESET == 27) + #define FXAA_QUALITY__PS 10 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 4.0 + #define FXAA_QUALITY__P9 8.0 +#elif (FXAA_QUALITY__PRESET == 28) + #define FXAA_QUALITY__PS 11 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 4.0 + #define FXAA_QUALITY__P10 8.0 +#elif (FXAA_QUALITY__PRESET == 29) + #define FXAA_QUALITY__PS 12 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.5 + #define FXAA_QUALITY__P2 2.0 + #define FXAA_QUALITY__P3 2.0 + #define FXAA_QUALITY__P4 2.0 + #define FXAA_QUALITY__P5 2.0 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 2.0 + #define FXAA_QUALITY__P10 4.0 + #define FXAA_QUALITY__P11 8.0 +#elif (FXAA_QUALITY__PRESET == 39) + #define FXAA_QUALITY__PS 12 + #define FXAA_QUALITY__P0 1.0 + #define FXAA_QUALITY__P1 1.0 + #define FXAA_QUALITY__P2 1.0 + #define FXAA_QUALITY__P3 1.0 + #define FXAA_QUALITY__P4 1.0 + #define FXAA_QUALITY__P5 1.5 + #define FXAA_QUALITY__P6 2.0 + #define FXAA_QUALITY__P7 2.0 + #define FXAA_QUALITY__P8 2.0 + #define FXAA_QUALITY__P9 2.0 + #define FXAA_QUALITY__P10 4.0 + #define FXAA_QUALITY__P11 8.0 +#endif + +FxaaFloat4 FxaaPixelShader(FxaaFloat2 pos, FxaaTex tex, FxaaFloat2 fxaaQualityRcpFrame, + FxaaFloat fxaaQualitySubpix, FxaaFloat fxaaQualityEdgeThreshold, FxaaFloat fxaaQualityEdgeThresholdMin) +{ + FxaaFloat2 posM; + posM.x = pos.x; + posM.y = pos.y; + #if (FXAA_GATHER4_ALPHA == 1) + #if (FXAA_DISCARD == 0) + FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); + #if (FXAA_GREEN_AS_LUMA == 0) + #define lumaM rgbyM.w + #else + #define lumaM rgbyM.y + #endif + #endif + #if (FXAA_GREEN_AS_LUMA == 0) + FxaaFloat4 luma4A = FxaaTexAlpha4(tex, posM); + FxaaFloat4 luma4B = FxaaTexOffAlpha4(tex, posM, FxaaInt2(-1, -1)); + #else + FxaaFloat4 luma4A = FxaaTexGreen4(tex, posM); + FxaaFloat4 luma4B = FxaaTexOffGreen4(tex, posM, FxaaInt2(-1, -1)); + #endif + #if (FXAA_DISCARD == 1) + #define lumaM luma4A.w + #endif + #define lumaE luma4A.z + #define lumaS luma4A.x + #define lumaSE luma4A.y + #define lumaNW luma4B.w + #define lumaN luma4B.z + #define lumaW luma4B.x + #else + FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); + #if (FXAA_GREEN_AS_LUMA == 0) + #define lumaM rgbyM.w + #else + #define lumaM rgbyM.y + #endif + FxaaFloat lumaS = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0, 1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 0), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaN = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 0), fxaaQualityRcpFrame.xy)); + #endif +/*--------------------------------------------------------------------------*/ + FxaaFloat maxSM = max(lumaS, lumaM); + FxaaFloat minSM = min(lumaS, lumaM); + FxaaFloat maxESM = max(lumaE, maxSM); + FxaaFloat minESM = min(lumaE, minSM); + FxaaFloat maxWN = max(lumaN, lumaW); + FxaaFloat minWN = min(lumaN, lumaW); + FxaaFloat rangeMax = max(maxWN, maxESM); + FxaaFloat rangeMin = min(minWN, minESM); + FxaaFloat rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold; + FxaaFloat range = rangeMax - rangeMin; + FxaaFloat rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled); + FxaaBool earlyExit = range < rangeMaxClamped; +/*--------------------------------------------------------------------------*/ + if(earlyExit) + #if (FXAA_DISCARD == 1) + FxaaDiscard; + #else + return rgbyM; + #endif +/*--------------------------------------------------------------------------*/ + #if (FXAA_GATHER4_ALPHA == 0) + FxaaFloat lumaNW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); + #else + FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(1, -1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); + #endif +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNS = lumaN + lumaS; + FxaaFloat lumaWE = lumaW + lumaE; + FxaaFloat subpixRcpRange = 1.0/range; + FxaaFloat subpixNSWE = lumaNS + lumaWE; + FxaaFloat edgeHorz1 = (-2.0 * lumaM) + lumaNS; + FxaaFloat edgeVert1 = (-2.0 * lumaM) + lumaWE; +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNESE = lumaNE + lumaSE; + FxaaFloat lumaNWNE = lumaNW + lumaNE; + FxaaFloat edgeHorz2 = (-2.0 * lumaE) + lumaNESE; + FxaaFloat edgeVert2 = (-2.0 * lumaN) + lumaNWNE; +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNWSW = lumaNW + lumaSW; + FxaaFloat lumaSWSE = lumaSW + lumaSE; + FxaaFloat edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2); + FxaaFloat edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2); + FxaaFloat edgeHorz3 = (-2.0 * lumaW) + lumaNWSW; + FxaaFloat edgeVert3 = (-2.0 * lumaS) + lumaSWSE; + FxaaFloat edgeHorz = abs(edgeHorz3) + edgeHorz4; + FxaaFloat edgeVert = abs(edgeVert3) + edgeVert4; +/*--------------------------------------------------------------------------*/ + FxaaFloat subpixNWSWNESE = lumaNWSW + lumaNESE; + FxaaFloat lengthSign = fxaaQualityRcpFrame.x; + FxaaBool horzSpan = edgeHorz >= edgeVert; + FxaaFloat subpixA = subpixNSWE * 2.0 + subpixNWSWNESE; +/*--------------------------------------------------------------------------*/ + if(!horzSpan) lumaN = lumaW; + if(!horzSpan) lumaS = lumaE; + if(horzSpan) lengthSign = fxaaQualityRcpFrame.y; + FxaaFloat subpixB = (subpixA * (1.0/12.0)) - lumaM; +/*--------------------------------------------------------------------------*/ + FxaaFloat gradientN = lumaN - lumaM; + FxaaFloat gradientS = lumaS - lumaM; + FxaaFloat lumaNN = lumaN + lumaM; + FxaaFloat lumaSS = lumaS + lumaM; + FxaaBool pairN = abs(gradientN) >= abs(gradientS); + FxaaFloat gradient = max(abs(gradientN), abs(gradientS)); + if(pairN) lengthSign = -lengthSign; + FxaaFloat subpixC = FxaaSat(abs(subpixB) * subpixRcpRange); +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posB; + posB.x = posM.x; + posB.y = posM.y; + FxaaFloat2 offNP; + offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x; + offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y; + if(!horzSpan) posB.x += lengthSign * 0.5; + if( horzSpan) posB.y += lengthSign * 0.5; +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posN; + posN.x = posB.x - offNP.x * FXAA_QUALITY__P0; + posN.y = posB.y - offNP.y * FXAA_QUALITY__P0; + FxaaFloat2 posP; + posP.x = posB.x + offNP.x * FXAA_QUALITY__P0; + posP.y = posB.y + offNP.y * FXAA_QUALITY__P0; + FxaaFloat subpixD = ((-2.0)*subpixC) + 3.0; + FxaaFloat lumaEndN = FxaaLuma(FxaaTexTop(tex, posN)); + FxaaFloat subpixE = subpixC * subpixC; + FxaaFloat lumaEndP = FxaaLuma(FxaaTexTop(tex, posP)); +/*--------------------------------------------------------------------------*/ + if(!pairN) lumaNN = lumaSS; + FxaaFloat gradientScaled = gradient * 1.0/4.0; + FxaaFloat lumaMM = lumaM - lumaNN * 0.5; + FxaaFloat subpixF = subpixD * subpixE; + FxaaBool lumaMLTZero = lumaMM < 0.0; +/*--------------------------------------------------------------------------*/ + lumaEndN -= lumaNN * 0.5; + lumaEndP -= lumaNN * 0.5; + FxaaBool doneN = abs(lumaEndN) >= gradientScaled; + FxaaBool doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P1; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P1; + FxaaBool doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P1; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P1; +/*--------------------------------------------------------------------------*/ + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P2; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P2; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P2; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P2; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 3) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P3; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P3; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P3; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P3; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 4) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P4; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P4; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P4; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P4; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 5) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P5; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P5; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P5; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P5; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 6) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P6; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P6; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P6; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P6; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 7) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P7; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P7; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P7; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P7; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 8) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P8; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P8; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P8; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P8; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 9) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P9; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P9; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P9; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P9; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 10) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P10; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P10; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P10; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P10; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 11) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P11; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P11; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P11; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P11; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY__PS > 12) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P12; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P12; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P12; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P12; +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } +/*--------------------------------------------------------------------------*/ + FxaaFloat dstN = posM.x - posN.x; + FxaaFloat dstP = posP.x - posM.x; + if(!horzSpan) dstN = posM.y - posN.y; + if(!horzSpan) dstP = posP.y - posM.y; +/*--------------------------------------------------------------------------*/ + FxaaBool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero; + FxaaFloat spanLength = (dstP + dstN); + FxaaBool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero; + FxaaFloat spanLengthRcp = 1.0/spanLength; +/*--------------------------------------------------------------------------*/ + FxaaBool directionN = dstN < dstP; + FxaaFloat dst = min(dstN, dstP); + FxaaBool goodSpan = directionN ? goodSpanN : goodSpanP; + FxaaFloat subpixG = subpixF * subpixF; + FxaaFloat pixelOffset = (dst * (-spanLengthRcp)) + 0.5; + FxaaFloat subpixH = subpixG * fxaaQualitySubpix; +/*--------------------------------------------------------------------------*/ + FxaaFloat pixelOffsetGood = goodSpan ? pixelOffset : 0.0; + FxaaFloat pixelOffsetSubpix = max(pixelOffsetGood, subpixH); + if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign; + if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign; + #if (FXAA_DISCARD == 1) + return FxaaTexTop(tex, posM); + #else + return FxaaFloat4(FxaaTexTop(tex, posM).xyz, lumaM); + #endif +} + +uniform vec2 ReciprocalResolution; + +void main() +{ + FragColor = FxaaPixelShader(TexCoord, InputTexture, ReciprocalResolution, 0.75f, 0.166f, 0.0833f); +} + +#endif // FXAA_LUMA_PASS From 201ae3c60f22be1bfd80a33c3968401c7ae804ce Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Fri, 30 Sep 2016 15:02:22 -0500 Subject: [PATCH 47/51] Added OverlayID() for retrieving psprite layer numbers. --- src/p_pspr.cpp | 19 +++++++++++++++++++ wadsrc/static/actors/actor.txt | 1 + 2 files changed, 20 insertions(+) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 67a447f61..fab7e38d8 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -1049,6 +1049,25 @@ DEFINE_ACTION_FUNCTION(AActor, A_OverlayFlags) return 0; } +//--------------------------------------------------------------------------- +// +// PROC OverlayID +// Because non-action functions cannot acquire the ID of the overlay... +//--------------------------------------------------------------------------- + +DEFINE_ACTION_FUNCTION(AActor, OverlayID) +{ + PARAM_ACTION_PROLOGUE; + + if (ACTION_CALL_FROM_PSPRITE()) + { + ACTION_RETURN_INT(stateinfo->mPSPIndex); + } + ACTION_RETURN_INT(0); +} + + + //--------------------------------------------------------------------------- // // PROC A_Lower diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index c82be96cd..44b801f51 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -57,6 +57,7 @@ ACTOR Actor native //: Thinker native float GetSpriteAngle(int ptr = AAPTR_DEFAULT); native float GetSpriteRotation(int ptr = AAPTR_DEFAULT); native int GetMissileDamage(int mask, int add, int ptr = AAPTR_DEFAULT); + action native int OverlayID(); // Action functions // Meh, MBF redundant functions. Only for DeHackEd support. From 41ab08ee4716b5e2e7da10bf52b4ce5c3ed49321 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 3 Oct 2016 11:00:26 +0200 Subject: [PATCH 48/51] - fixed: TVector::Resized needs to consider that the input vector has a length of 0. In this case just performing the normal calculations results in an invalid vector. --- src/vectors.h | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/vectors.h b/src/vectors.h index 00a65df50..1852609f2 100644 --- a/src/vectors.h +++ b/src/vectors.h @@ -556,17 +556,29 @@ struct TVector3 // Resizes this vector to be the specified length (if it is not 0) TVector3 &MakeResize(double len) { - double scale = len / Length(); - X = vec_t(X * scale); - Y = vec_t(Y * scale); - Z = vec_t(Z * scale); + double vlen = Length(); + if (vlen != 0.) + { + double scale = len / vlen; + X = vec_t(X * scale); + Y = vec_t(Y * scale); + Z = vec_t(Z * scale); + } return *this; } TVector3 Resized(double len) { - double scale = len / Length(); - return{ vec_t(X * scale), vec_t(Y * scale), vec_t(Z * scale) }; + double vlen = Length(); + if (vlen != 0.) + { + double scale = len / vlen; + return{ vec_t(X * scale), vec_t(Y * scale), vec_t(Z * scale) }; + } + else + { + return *this; + } } // Dot product From 4eb5f10b02cc2b1844f0a6894f3a7005049d767a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 3 Oct 2016 16:09:32 +0200 Subject: [PATCH 49/51] - use normals to have proper light attenuation. So far only implemented for walls and flats. Models are planned but need some thinking about how to efficiently collect all required lights for an object. --- src/gl/data/gl_matrix.cpp | 2 +- src/gl/data/gl_vertexbuffer.cpp | 2 ++ src/gl/data/gl_vertexbuffer.h | 9 +++++- src/gl/models/gl_models.cpp | 2 ++ src/gl/models/gl_voxels.cpp | 2 ++ src/gl/renderer/gl_renderstate.cpp | 5 ++++ src/gl/renderer/gl_renderstate.h | 13 +++++++++ src/gl/scene/gl_flats.cpp | 10 +++++-- src/gl/scene/gl_portal.cpp | 4 +-- src/gl/scene/gl_skydome.cpp | 1 + src/gl/scene/gl_sprite.cpp | 1 + src/gl/scene/gl_wall.h | 9 ++++++ src/gl/scene/gl_walls.cpp | 4 +-- src/gl/scene/gl_walls_draw.cpp | 8 ++--- src/gl/shaders/gl_shader.cpp | 22 +++++++++----- src/gl/shaders/gl_shader.h | 4 ++- wadsrc/static/shaders/glsl/main.fp | 39 +++++++++++++++++++++++-- wadsrc/static/shaders/glsl/main.vp | 7 +++++ wadsrc/static/shaders/glsl/shaderdefs.i | 2 ++ 19 files changed, 122 insertions(+), 24 deletions(-) diff --git a/src/gl/data/gl_matrix.cpp b/src/gl/data/gl_matrix.cpp index d8017ad40..115882857 100644 --- a/src/gl/data/gl_matrix.cpp +++ b/src/gl/data/gl_matrix.cpp @@ -442,7 +442,7 @@ VSMatrix::computeNormalMatrix(const FLOATTYPE *aMatrix) mMat3x3[1] * (mMat3x3[5] * mMat3x3[6] - mMat3x3[8] * mMat3x3[3]) + mMat3x3[2] * (mMat3x3[3] * mMat3x3[7] - mMat3x3[4] * mMat3x3[6]); - invDet = 1.0f/det; + invDet = 1.0/det; mMatrix[0] = (mMat3x3[4] * mMat3x3[8] - mMat3x3[5] * mMat3x3[7]) * invDet; mMatrix[1] = (mMat3x3[5] * mMat3x3[6] - mMat3x3[8] * mMat3x3[3]) * invDet; diff --git a/src/gl/data/gl_vertexbuffer.cpp b/src/gl/data/gl_vertexbuffer.cpp index 4e76b51cb..d14599eb8 100644 --- a/src/gl/data/gl_vertexbuffer.cpp +++ b/src/gl/data/gl_vertexbuffer.cpp @@ -71,6 +71,7 @@ void FSimpleVertexBuffer::BindVBO() glEnableVertexAttribArray(VATTR_TEXCOORD); glEnableVertexAttribArray(VATTR_COLOR); glDisableVertexAttribArray(VATTR_VERTEX2); + glDisableVertexAttribArray(VATTR_NORMAL); } else { @@ -236,6 +237,7 @@ void FFlatVertexBuffer::BindVBO() glEnableVertexAttribArray(VATTR_TEXCOORD); glDisableVertexAttribArray(VATTR_COLOR); glDisableVertexAttribArray(VATTR_VERTEX2); + glDisableVertexAttribArray(VATTR_NORMAL); } else { diff --git a/src/gl/data/gl_vertexbuffer.h b/src/gl/data/gl_vertexbuffer.h index 596de35d9..f777118fd 100644 --- a/src/gl/data/gl_vertexbuffer.h +++ b/src/gl/data/gl_vertexbuffer.h @@ -271,6 +271,7 @@ struct FModelVertex { float x, y, z; // world position float u, v; // texture coordinates + unsigned packedNormal; // normal vector as GL_INT_2_10_10_10_REV. void Set(float xx, float yy, float zz, float uu, float vv) { @@ -283,7 +284,13 @@ struct FModelVertex void SetNormal(float nx, float ny, float nz) { - // GZDoom currently doesn't use normals. This function is so that the high level code can pretend it does. + /* + int inx = int(nx * 512); + int iny = int(ny * 512); + int inz = int(nz * 512); + packedNormal = 0x40000000 | ((inx & 1023) << 20) | ((iny & 1023) << 10) | (inz & 1023); + */ + packedNormal = 0; // Per-pixel lighting for models isn't implemented yet so leave this at 0 for now. } }; diff --git a/src/gl/models/gl_models.cpp b/src/gl/models/gl_models.cpp index 91bd9131e..f3dfbd569 100644 --- a/src/gl/models/gl_models.cpp +++ b/src/gl/models/gl_models.cpp @@ -119,6 +119,7 @@ void FModelVertexBuffer::BindVBO() glEnableVertexAttribArray(VATTR_VERTEX); glEnableVertexAttribArray(VATTR_TEXCOORD); glEnableVertexAttribArray(VATTR_VERTEX2); + glEnableVertexAttribArray(VATTR_NORMAL); glDisableVertexAttribArray(VATTR_COLOR); } else @@ -245,6 +246,7 @@ unsigned int FModelVertexBuffer::SetupFrame(unsigned int frame1, unsigned int fr glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame1].x); glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame1].u); glVertexAttribPointer(VATTR_VERTEX2, 3, GL_FLOAT, false, sizeof(FModelVertex), &VMO[frame2].x); + glVertexAttribPointer(VATTR_NORMAL, 4, GL_UNSIGNED_INT_2_10_10_10_REV, false, sizeof(FModelVertex), &VMO[frame2].packedNormal); } else { diff --git a/src/gl/models/gl_voxels.cpp b/src/gl/models/gl_voxels.cpp index 6213eb006..288b1a9db 100644 --- a/src/gl/models/gl_voxels.cpp +++ b/src/gl/models/gl_voxels.cpp @@ -248,6 +248,7 @@ void FVoxelModel::AddFace(int x1, int y1, int z1, int x2, int y2, int z2, int x3 FModelVertex vert; unsigned int indx[4]; + vert.packedNormal = 0; // currently this is not being used for voxels. vert.u = (((col & 15) * 255 / 16) + 7) / 255.f; vert.v = (((col / 16) * 255 / 16) + 7) / 255.f; @@ -271,6 +272,7 @@ void FVoxelModel::AddFace(int x1, int y1, int z1, int x2, int y2, int z2, int x3 vert.y = -z3 + PivotZ; indx[3] = AddVertex(vert, check); + mIndices.Push(indx[0]); mIndices.Push(indx[1]); mIndices.Push(indx[3]); diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 967296cb8..a8c9c5da2 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -141,6 +141,7 @@ bool FRenderState::ApplyShader() } glVertexAttrib4fv(VATTR_COLOR, mColor.vec); + glVertexAttrib4fv(VATTR_NORMAL, mNormal.vec); activeShader->muDesaturation.Set(mDesaturation / 255.f); activeShader->muFogEnabled.Set(fogset); @@ -269,12 +270,16 @@ bool FRenderState::ApplyShader() if (mModelMatrixEnabled) { mModelMatrix.matrixToGL(activeShader->modelmatrix_index); + VSMatrix norm; + norm.computeNormalMatrix(mModelMatrix); + mNormalModelMatrix.matrixToGL(activeShader->normalmodelmatrix_index); activeShader->currentModelMatrixState = true; } else if (activeShader->currentModelMatrixState) { activeShader->currentModelMatrixState = false; identityMatrix.matrixToGL(activeShader->modelmatrix_index); + identityMatrix.matrixToGL(activeShader->normalmodelmatrix_index); } return true; } diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h index 1c0a20348..6a1856910 100644 --- a/src/gl/renderer/gl_renderstate.h +++ b/src/gl/renderer/gl_renderstate.h @@ -90,6 +90,7 @@ class FRenderState float mShaderTimer; FVertexBuffer *mVertexBuffer, *mCurrentVertexBuffer; + FStateVec4 mNormal; FStateVec4 mColor; FStateVec4 mCameraPos; FStateVec4 mGlowTop, mGlowBottom; @@ -119,6 +120,8 @@ public: VSMatrix mViewMatrix; VSMatrix mModelMatrix; VSMatrix mTextureMatrix; + VSMatrix mNormalViewMatrix; + VSMatrix mNormalModelMatrix; FRenderState() { @@ -180,6 +183,16 @@ public: void SetClipHeight(float height, float direction); + void SetNormal(FVector3 norm) + { + mNormal.Set(norm.X, norm.Y, norm.Z, 0.f); + } + + void SetNormal(float x, float y, float z) + { + mNormal.Set(x, y, z, 0.f); + } + void SetColor(float r, float g, float b, float a = 1.f, int desat = 0) { mColor.Set(r, g, b, a); diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index 90f3be66f..394ca1626 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -374,6 +374,7 @@ void GLFlat::Draw(int pass, bool trans) // trans only has meaning for GLPASS_LIG } #endif + gl_RenderState.SetNormal(plane.plane.Normal().X, plane.plane.Normal().Z, plane.plane.Normal().Y); switch (pass) { @@ -502,6 +503,11 @@ inline void GLFlat::PutFlat(bool fog) void GLFlat::Process(sector_t * model, int whichplane, bool fog) { plane.GetFromSector(model, whichplane); + if (whichplane != int(ceiling)) + { + // Flip the normal if the source plane has a different orientation than what we are about to render. + plane.plane.FlipVert(); + } if (!fog) { @@ -641,7 +647,7 @@ void GLFlat::ProcessSector(sector_t * frontsector) Colormap.CopyFrom3DLight(light); } renderstyle = STYLE_Translucent; - Process(frontsector, false, false); + Process(frontsector, sector_t::floor, false); } } @@ -700,7 +706,7 @@ void GLFlat::ProcessSector(sector_t * frontsector) Colormap.CopyFrom3DLight(light); } renderstyle = STYLE_Translucent; - Process(frontsector, true, false); + Process(frontsector, sector_t::ceiling, false); } } diff --git a/src/gl/scene/gl_portal.cpp b/src/gl/scene/gl_portal.cpp index 4a7fa9d7a..50693d75c 100644 --- a/src/gl/scene/gl_portal.cpp +++ b/src/gl/scene/gl_portal.cpp @@ -1217,7 +1217,7 @@ void GLEEHorizonPortal::DrawContents() if (sector->GetTexture(sector_t::ceiling) != skyflatnum) { GLHorizonInfo horz; - horz.plane.GetFromSector(sector, true); + horz.plane.GetFromSector(sector, sector_t::ceiling); horz.lightlevel = gl_ClampLight(sector->GetCeilingLight()); horz.colormap = sector->ColorMap; if (portal->mType == PORTS_PLANE) @@ -1230,7 +1230,7 @@ void GLEEHorizonPortal::DrawContents() if (sector->GetTexture(sector_t::floor) != skyflatnum) { GLHorizonInfo horz; - horz.plane.GetFromSector(sector, false); + horz.plane.GetFromSector(sector, sector_t::floor); horz.lightlevel = gl_ClampLight(sector->GetFloorLight()); horz.colormap = sector->ColorMap; if (portal->mType == PORTS_PLANE) diff --git a/src/gl/scene/gl_skydome.cpp b/src/gl/scene/gl_skydome.cpp index 1653d2bb8..015b42016 100644 --- a/src/gl/scene/gl_skydome.cpp +++ b/src/gl/scene/gl_skydome.cpp @@ -114,6 +114,7 @@ void FSkyVertexBuffer::BindVBO() glEnableVertexAttribArray(VATTR_TEXCOORD); glEnableVertexAttribArray(VATTR_COLOR); glDisableVertexAttribArray(VATTR_VERTEX2); + glDisableVertexAttribArray(VATTR_NORMAL); } else { diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index 19753f742..ab88f2f9c 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -406,6 +406,7 @@ void GLSprite::Draw(int pass) gl_RenderState.Apply(); FVector3 v[4]; + gl_RenderState.SetNormal(0, 0, 0); CalculateVertices(v); FQuadDrawer qd; diff --git a/src/gl/scene/gl_wall.h b/src/gl/scene/gl_wall.h index 32dc6ee5b..143029ba7 100644 --- a/src/gl/scene/gl_wall.h +++ b/src/gl/scene/gl_wall.h @@ -60,6 +60,15 @@ struct GLSeg float x1,x2; float y1,y2; float fracleft, fracright; // fractional offset of the 2 vertices on the linedef + + FVector3 Normal() const + { + // we do not use the vector math inlines here because they are not optimized for speed but accuracy in the playsim + float x = y2 - y1; + float y = x1 - x2; + float length = sqrt(x*x + y*y); + return FVector3(x / length, 0, y / length); + } }; struct texcoord diff --git a/src/gl/scene/gl_walls.cpp b/src/gl/scene/gl_walls.cpp index 3a7baec33..db16a941a 100644 --- a/src/gl/scene/gl_walls.cpp +++ b/src/gl/scene/gl_walls.cpp @@ -470,7 +470,7 @@ bool GLWall::DoHorizon(seg_t * seg,sector_t * fs, vertex_t * v1,vertex_t * v2) } else { - hi.plane.GetFromSector(fs, true); + hi.plane.GetFromSector(fs, sector_t::ceiling); hi.lightlevel = gl_ClampLight(fs->GetCeilingLight()); hi.colormap = fs->ColorMap; @@ -498,7 +498,7 @@ bool GLWall::DoHorizon(seg_t * seg,sector_t * fs, vertex_t * v1,vertex_t * v2) } else { - hi.plane.GetFromSector(fs, false); + hi.plane.GetFromSector(fs, sector_t::floor); hi.lightlevel = gl_ClampLight(fs->GetFloorLight()); hi.colormap = fs->ColorMap; diff --git a/src/gl/scene/gl_walls_draw.cpp b/src/gl/scene/gl_walls_draw.cpp index a7884b51a..dbc43fd22 100644 --- a/src/gl/scene/gl_walls_draw.cpp +++ b/src/gl/scene/gl_walls_draw.cpp @@ -254,14 +254,13 @@ void GLWall::RenderMirrorSurface() if (GLRenderer->mirrortexture == NULL) return; // For the sphere map effect we need a normal of the mirror surface, - Vector v(glseg.y2-glseg.y1, 0 ,-glseg.x2+glseg.x1); - v.Normalize(); + FVector3 v = glseg.Normal(); if (!gl.legacyMode) { // we use texture coordinates and texture matrix to pass the normal stuff to the shader so that the default vertex buffer format can be used as is. - tcs[LOLFT].u = tcs[LORGT].u = tcs[UPLFT].u = tcs[UPRGT].u = v.X(); - tcs[LOLFT].v = tcs[LORGT].v = tcs[UPLFT].v = tcs[UPRGT].v = v.Z(); + tcs[LOLFT].u = tcs[LORGT].u = tcs[UPLFT].u = tcs[UPRGT].u = v.X; + tcs[LOLFT].v = tcs[LORGT].v = tcs[UPLFT].v = tcs[UPRGT].v = v.Z; gl_RenderState.EnableTextureMatrix(true); gl_RenderState.mTextureMatrix.computeNormalMatrix(gl_RenderState.mViewMatrix); @@ -414,6 +413,7 @@ void GLWall::RenderTranslucentWall() //========================================================================== void GLWall::Draw(int pass) { + gl_RenderState.SetNormal(glseg.Normal()); switch (pass) { case GLPASS_LIGHTSONLY: diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index d4e05dfa8..8f78e22e4 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -179,6 +179,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * glBindAttribLocation(hShader, VATTR_TEXCOORD, "aTexCoord"); glBindAttribLocation(hShader, VATTR_COLOR, "aColor"); glBindAttribLocation(hShader, VATTR_VERTEX2, "aVertex2"); + glBindAttribLocation(hShader, VATTR_NORMAL, "aNormal"); glLinkProgram(hShader); @@ -241,6 +242,8 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * texturematrix_index = glGetUniformLocation(hShader, "TextureMatrix"); vertexmatrix_index = glGetUniformLocation(hShader, "uQuadVertices"); texcoordmatrix_index = glGetUniformLocation(hShader, "uQuadTexCoords"); + normalviewmatrix_index = glGetUniformLocation(hShader, "NormalViewMatrix"); + normalmodelmatrix_index = glGetUniformLocation(hShader, "NormalModelMatrix"); quadmode_index = glGetUniformLocation(hShader, "uQuadMode"); if (!gl.legacyMode && !(gl.flags & RFL_SHADER_STORAGE_BUFFER)) @@ -328,14 +331,14 @@ FShader *FShaderManager::Compile (const char *ShaderName, const char *ShaderPath // //========================================================================== -void FShader::ApplyMatrices(VSMatrix *proj, VSMatrix *view) +void FShader::ApplyMatrices(VSMatrix *proj, VSMatrix *view, VSMatrix *norm) { Bind(); glUniformMatrix4fv(projectionmatrix_index, 1, false, proj->get()); glUniformMatrix4fv(viewmatrix_index, 1, false, view->get()); + glUniformMatrix4fv(normalviewmatrix_index, 1, false, norm->get()); } - //========================================================================== // // @@ -556,23 +559,26 @@ void FShaderManager::ApplyMatrices(VSMatrix *proj, VSMatrix *view) } else { + VSMatrix norm; + norm.computeNormalMatrix(*view); + for (int i = 0; i < 4; i++) { - mTextureEffects[i]->ApplyMatrices(proj, view); - mTextureEffectsNAT[i]->ApplyMatrices(proj, view); + mTextureEffects[i]->ApplyMatrices(proj, view, &norm); + mTextureEffectsNAT[i]->ApplyMatrices(proj, view, &norm); } - mTextureEffects[4]->ApplyMatrices(proj, view); + mTextureEffects[4]->ApplyMatrices(proj, view, &norm); if (gl_fuzztype != 0) { - mTextureEffects[4 + gl_fuzztype]->ApplyMatrices(proj, view); + mTextureEffects[4 + gl_fuzztype]->ApplyMatrices(proj, view, &norm); } for (unsigned i = 12; i < mTextureEffects.Size(); i++) { - mTextureEffects[i]->ApplyMatrices(proj, view); + mTextureEffects[i]->ApplyMatrices(proj, view, &norm); } for (int i = 0; i < MAX_EFFECTS; i++) { - mEffectShaders[i]->ApplyMatrices(proj, view); + mEffectShaders[i]->ApplyMatrices(proj, view, &norm); } if (mActiveShader != NULL) mActiveShader->Bind(); } diff --git a/src/gl/shaders/gl_shader.h b/src/gl/shaders/gl_shader.h index 343942321..679ae1172 100644 --- a/src/gl/shaders/gl_shader.h +++ b/src/gl/shaders/gl_shader.h @@ -285,7 +285,9 @@ class FShader int lights_index; int projectionmatrix_index; int viewmatrix_index; + int normalviewmatrix_index; int modelmatrix_index; + int normalmodelmatrix_index; int texturematrix_index; public: int vertexmatrix_index; @@ -318,7 +320,7 @@ public: bool Bind(); unsigned int GetHandle() const { return hShader; } - void ApplyMatrices(VSMatrix *proj, VSMatrix *view); + void ApplyMatrices(VSMatrix *proj, VSMatrix *view, VSMatrix *norm); }; diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 95ac874b7..fb1983fc7 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -1,6 +1,8 @@ in vec4 pixelpos; in vec2 glowdist; +in vec4 vWorldNormal; +in vec4 vEyeNormal; in vec4 vTexCoord; in vec4 vColor; @@ -121,6 +123,37 @@ float R_DoomLightingEquation(float light) return lightscale; } +//=========================================================================== +// +// Standard lambertian diffuse light calculation +// +//=========================================================================== + +float diffuseContribution(vec3 lightDirection, vec3 normal) +{ + return max(dot(normal, lightDirection), 0.0f); +} + +//=========================================================================== +// +// Calculates the brightness of a dynamic point light +// Todo: Find a better way to define which lighting model to use. +// (Specular mode has been removed for now.) +// +//=========================================================================== + +float pointLightAttenuation(vec4 lightpos) +{ + float attenuation = max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; + #if 0 + return attenuation; + #else + vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz); + float diffuseAmount = diffuseContribution(lightDirection, normalize(vWorldNormal.xyz)); + return attenuation * diffuseAmount; + #endif +} + //=========================================================================== // // Calculate light @@ -196,7 +229,7 @@ vec4 getLightColor(float fogdist, float fogfactor) vec4 lightpos = lights[i]; vec4 lightcolor = lights[i+1]; - lightcolor.rgb *= max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; + lightcolor.rgb *= pointLightAttenuation(lightpos); dynlight.rgb += lightcolor.rgb; } // @@ -207,7 +240,7 @@ vec4 getLightColor(float fogdist, float fogfactor) vec4 lightpos = lights[i]; vec4 lightcolor = lights[i+1]; - lightcolor.rgb *= max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; + lightcolor.rgb *= pointLightAttenuation(lightpos); dynlight.rgb -= lightcolor.rgb; } } @@ -289,7 +322,7 @@ void main() vec4 lightpos = lights[i]; vec4 lightcolor = lights[i+1]; - lightcolor.rgb *= max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; + lightcolor.rgb *= pointLightAttenuation(lightpos); addlight.rgb += lightcolor.rgb; } frag.rgb = clamp(frag.rgb + desaturate(addlight).rgb, 0.0, 1.0); diff --git a/wadsrc/static/shaders/glsl/main.vp b/wadsrc/static/shaders/glsl/main.vp index a2c1bac5b..1de8854c0 100644 --- a/wadsrc/static/shaders/glsl/main.vp +++ b/wadsrc/static/shaders/glsl/main.vp @@ -4,8 +4,12 @@ in vec2 aTexCoord; in vec4 aColor; #ifndef SIMPLE // we do not need these for simple shaders in vec4 aVertex2; +in vec4 aNormal; out vec4 pixelpos; out vec2 glowdist; + +out vec4 vWorldNormal; +out vec4 vEyeNormal; #endif out vec4 vTexCoord; @@ -54,6 +58,9 @@ void main() gl_ClipDistance[3] = -((uSplitTopPlane.w + uSplitTopPlane.x * worldcoord.x + uSplitTopPlane.y * worldcoord.z) * uSplitTopPlane.z) - worldcoord.y; gl_ClipDistance[4] = worldcoord.y + ((uSplitBottomPlane.w + uSplitBottomPlane.x * worldcoord.x + uSplitBottomPlane.y * worldcoord.z) * uSplitBottomPlane.z); } + + vWorldNormal = NormalModelMatrix * aNormal; + vEyeNormal = NormalViewMatrix * vWorldNormal; #endif #ifdef SPHEREMAP diff --git a/wadsrc/static/shaders/glsl/shaderdefs.i b/wadsrc/static/shaders/glsl/shaderdefs.i index 3701694bc..8c5697a66 100644 --- a/wadsrc/static/shaders/glsl/shaderdefs.i +++ b/wadsrc/static/shaders/glsl/shaderdefs.i @@ -56,5 +56,7 @@ uniform int uQuadMode; uniform mat4 ProjectionMatrix; uniform mat4 ViewMatrix; uniform mat4 ModelMatrix; +uniform mat4 NormalViewMatrix; +uniform mat4 NormalModelMatrix; uniform mat4 TextureMatrix; From 7ab7fc9a57f8d329f53e9643586eb1ed958afb51 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 3 Oct 2016 16:21:50 +0200 Subject: [PATCH 50/51] - seems I missed this part... --- src/gl/dynlights/a_dynlight.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/gl/dynlights/a_dynlight.cpp b/src/gl/dynlights/a_dynlight.cpp index 20d0d6078..0e52eedd8 100644 --- a/src/gl/dynlights/a_dynlight.cpp +++ b/src/gl/dynlights/a_dynlight.cpp @@ -391,6 +391,16 @@ void ADynamicLight::UpdateLocation() Prev = target->Pos(); subsector = R_PointInSubsector(Prev); Sector = subsector->sector; + + // Some z-coordinate fudging to prevent the light from getting too close to the floor or ceiling planes. With proper attenuation this would render them invisible. + // A distance of 5 is needed so that the light's effect doesn't become too small. + if (Z() < target->floorz + 5.) SetZ(target->floorz + 5.); + else if (Z() > target->ceilingz - 5.) SetZ(target->ceilingz - 5.); + } + else + { + if (Z() < floorz + 5.) SetZ(floorz + 5.); + else if (Z() > ceilingz - 5.) SetZ(ceilingz - 5.); } From 5d99e7dafe28fbc92978c5b30ebcfed8013a4ff6 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Mon, 3 Oct 2016 22:13:33 +0300 Subject: [PATCH 51/51] Fixed compilation on platforms other than Windows --- src/g_shared/sbarinfo_commands.cpp | 4 ++-- src/gl/stereo3d/gl_interleaved3d.cpp | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 13c98d833..d105ab818 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -1187,12 +1187,12 @@ class CommandDrawNumber : public CommandDrawString if (!(cvartype == CVAR_Bool || cvartype == CVAR_Int)) { - sc.ScriptMessage("CVar '%s' is not an int or bool", cvarName); + sc.ScriptMessage("CVar '%s' is not an int or bool", cvarName.GetChars()); } } else { - sc.ScriptMessage("CVar '%s' does not exist", cvarName); + sc.ScriptMessage("CVar '%s' does not exist", cvarName.GetChars()); } if (parenthesized) sc.MustGetToken(')'); diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp index 329dec953..036a84b0b 100644 --- a/src/gl/stereo3d/gl_interleaved3d.cpp +++ b/src/gl/stereo3d/gl_interleaved3d.cpp @@ -104,10 +104,13 @@ void RowInterleaved3D::Present() const // Compute absolute offset from top of screen to top of current display window // because we need screen-relative, not window-relative, scan line parity int windowVOffset = 0; + +#ifdef _WIN32 if (! fullscreen) { I_SaveWindowedPos(); // update win_y CVAR windowVOffset = win_y; } +#endif // _WIN32 GLRenderer->mPresent3dRowShader->VerticalPixelOffset.Set( windowVOffset // fixme: vary with window location