mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-04-15 22:40:59 +00:00
Merge branch 'master' of https://github.com/coelckers/gzdoom
# Conflicts: # src/version.h
This commit is contained in:
commit
da42c9adf5
593 changed files with 11976 additions and 1645 deletions
|
@ -20,10 +20,10 @@ environment:
|
|||
CONFIGURATION: Release
|
||||
TOOLSET: v141_xp
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2017"
|
||||
- GENERATOR: "Visual Studio 15 2017 Win64"
|
||||
CONFIGURATION: Release
|
||||
TOOLSET: v141_xp
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2017"
|
||||
# - GENERATOR: "Visual Studio 15 2017 Win64"
|
||||
# CONFIGURATION: Release
|
||||
# TOOLSET: v141_xp
|
||||
# APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2017"
|
||||
- GENERATOR: "Visual Studio 14 2015 Win64"
|
||||
CONFIGURATION: Debug
|
||||
TOOLSET: v140
|
||||
|
|
|
@ -56,15 +56,15 @@ matrix:
|
|||
- os: linux
|
||||
compiler: clang
|
||||
env:
|
||||
- CLANG_VERSION=4.0
|
||||
- CLANG_VERSION=5.0
|
||||
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=MinSizeRel -DDYN_OPENAL=NO -DDYN_SNDFILE=NO -DDYN_MPG123=NO -DDYN_FLUIDSYNTH=NO"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-4.0
|
||||
- llvm-toolchain-trusty-5.0
|
||||
packages:
|
||||
- clang-4.0
|
||||
- clang-5.0
|
||||
- libstdc++-5-dev
|
||||
- libsdl2-dev
|
||||
- libgme-dev
|
||||
|
|
|
@ -15,8 +15,15 @@ include( CreateLaunchers )
|
|||
include( FindPackageHandleStandardArgs )
|
||||
|
||||
# Produce a warning if XP support will be missing.
|
||||
if( MSVC14 AND NOT CMAKE_GENERATOR_TOOLSET STREQUAL "v140_xp" )
|
||||
message( WARNING "This project supports Windows XP (including XP x64), but you must set the optional toolset to v140_xp manually to have it in your build! Use -T \"v140_xp\" from the command prompt." )
|
||||
if( MSVC )
|
||||
list( APPEND WINXP_TOOLSETS v140_xp v141_xp)
|
||||
list( FIND WINXP_TOOLSETS "${CMAKE_GENERATOR_TOOLSET}" HAVE_WINXP_SUPPORT)
|
||||
|
||||
if( HAVE_WINXP_SUPPORT EQUAL -1 )
|
||||
string( REPLACE ";" " or " WINXP_TOOLSETS_STR "${WINXP_TOOLSETS}" )
|
||||
message( WARNING "This project supports Windows XP but you must set the optional toolset to ${WINXP_TOOLSETS_STR} manually to have it in your build!\n"
|
||||
"Assign toolset's name to CMAKE_GENERATOR_TOOLSET variable or use -T <toolset> from the command prompt." )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Support cross compiling
|
||||
|
@ -323,6 +330,7 @@ add_subdirectory( gdtoa )
|
|||
add_subdirectory( wadsrc )
|
||||
add_subdirectory( wadsrc_bm )
|
||||
add_subdirectory( wadsrc_lights )
|
||||
add_subdirectory( wadsrc_extra )
|
||||
add_subdirectory( src )
|
||||
|
||||
if( NOT CMAKE_CROSSCOMPILING )
|
||||
|
|
|
@ -342,7 +342,7 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
|||
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm")
|
||||
set (USE_ARMV8 0 CACHE BOOL "Use ARMv8 instructions - Raspberry Pi 3")
|
||||
if (USE_ARMV8)
|
||||
set( CMAKE_CXX_FLAGS "-mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mtune=cortex-a53 -funsafe-math-optimizations -mhard-float -DNO_SSE ${CMAKE_CXX_FLAGS}" )
|
||||
set( CMAKE_CXX_FLAGS "-mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mtune=cortex-a53 -mhard-float -DNO_SSE ${CMAKE_CXX_FLAGS}" )
|
||||
else ()
|
||||
set( CMAKE_CXX_FLAGS "-mfpu=neon -DNO_SSE ${CMAKE_CXX_FLAGS}" )
|
||||
endif ()
|
||||
|
@ -744,6 +744,7 @@ set ( SWRENDER_SOURCES
|
|||
|
||||
set( POLYRENDER_SOURCES
|
||||
polyrenderer/poly_renderer.cpp
|
||||
polyrenderer/poly_renderthread.cpp
|
||||
polyrenderer/scene/poly_scene.cpp
|
||||
polyrenderer/scene/poly_portal.cpp
|
||||
polyrenderer/scene/poly_cull.cpp
|
||||
|
|
|
@ -1086,6 +1086,7 @@ public:
|
|||
|
||||
double projectilepassheight; // height for clipping projectile movement against this actor
|
||||
double CameraHeight; // Height of camera when used as such
|
||||
double CameraFOV;
|
||||
|
||||
double RadiusDamageFactor; // Radius damage factor
|
||||
double SelfDamageFactor;
|
||||
|
|
|
@ -184,6 +184,25 @@ bool FileExists (const char *filename)
|
|||
return stat(filename, &buff) == 0 && !(buff.st_mode & S_IFDIR);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DirExists
|
||||
//
|
||||
// Returns true if the given path exists and is a directory.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool DirExists(const char *filename)
|
||||
{
|
||||
struct stat buff;
|
||||
|
||||
// [RH] Empty filenames are never there
|
||||
if (filename == NULL || *filename == 0)
|
||||
return false;
|
||||
|
||||
return stat(filename, &buff) == 0 && (buff.st_mode & S_IFDIR);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DirEntryExists
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
int Q_filelength (FILE *f);
|
||||
bool FileExists (const char *filename);
|
||||
bool DirExists(const char *filename);
|
||||
bool DirEntryExists (const char *pathname);
|
||||
|
||||
extern FString progdir;
|
||||
|
|
|
@ -2431,12 +2431,12 @@ int D_LoadDehLumps(DehLumpSource source)
|
|||
{
|
||||
const int filenum = Wads.GetLumpFile(lumpnum);
|
||||
|
||||
if (FromIWAD == source && filenum > FWadCollection::IWAD_FILENUM)
|
||||
if (FromIWAD == source && filenum > Wads.GetIwadNum())
|
||||
{
|
||||
// No more DEHACKED lumps in IWAD
|
||||
break;
|
||||
}
|
||||
else if (FromPWADs == source && filenum <= FWadCollection::IWAD_FILENUM)
|
||||
else if (FromPWADs == source && filenum <= Wads.GetIwadNum())
|
||||
{
|
||||
// Skip DEHACKED lumps from IWAD
|
||||
continue;
|
||||
|
|
576
src/d_iwad.cpp
576
src/d_iwad.cpp
|
@ -48,80 +48,37 @@
|
|||
#include "gameconfigfile.h"
|
||||
#include "resourcefiles/resourcefile.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "doomerrors.h"
|
||||
#include "v_text.h"
|
||||
|
||||
CVAR (Bool, queryiwad, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
||||
CVAR (String, defaultiwad, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Clear check list
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FIWadManager::ClearChecks()
|
||||
{
|
||||
mLumpsFound.Resize(mIWads.Size());
|
||||
for(unsigned i=0;i<mLumpsFound.Size(); i++)
|
||||
{
|
||||
mLumpsFound[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Check one lump
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FIWadManager::CheckLumpName(const char *name)
|
||||
{
|
||||
for(unsigned i=0; i< mIWads.Size(); i++)
|
||||
{
|
||||
for(unsigned j=0; j < mIWads[i].Lumps.Size(); j++)
|
||||
{
|
||||
if (!mIWads[i].Lumps[j].CompareNoCase(name))
|
||||
{
|
||||
mLumpsFound[i] |= (1<<j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Returns check result
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FIWadManager::GetIWadInfo()
|
||||
{
|
||||
for(unsigned i=0; i< mIWads.Size(); i++)
|
||||
{
|
||||
if (mLumpsFound[i] == (1 << mIWads[i].Lumps.Size()) - 1)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Parses IWAD definitions
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize)
|
||||
void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize, FIWADInfo *result)
|
||||
{
|
||||
FScanner sc;
|
||||
int numblocks = 0;
|
||||
|
||||
sc.OpenMem("IWADINFO", data, datasize);
|
||||
while (sc.GetString())
|
||||
{
|
||||
if (sc.Compare("IWAD"))
|
||||
{
|
||||
FIWADInfo *iwad = &mIWads[mIWads.Reserve(1)];
|
||||
numblocks++;
|
||||
if (result && numblocks > 1)
|
||||
{
|
||||
sc.ScriptMessage("Multiple IWAD records ignored");
|
||||
// Skip the rest.
|
||||
break;
|
||||
}
|
||||
|
||||
FIWADInfo *iwad = result ? result : &mIWadInfos[mIWadInfos.Reserve(1)];
|
||||
sc.MustGetStringName("{");
|
||||
while (!sc.CheckString("}"))
|
||||
{
|
||||
|
@ -138,6 +95,17 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize)
|
|||
sc.MustGetString();
|
||||
iwad->Autoname = sc.String;
|
||||
}
|
||||
else if (sc.Compare("IWadname"))
|
||||
{
|
||||
sc.MustGetStringName("=");
|
||||
sc.MustGetString();
|
||||
iwad->IWadname = sc.String;
|
||||
if (sc.CheckString(","))
|
||||
{
|
||||
sc.MustGetNumber();
|
||||
iwad->prio = sc.Number;
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("Config"))
|
||||
{
|
||||
sc.MustGetStringName("=");
|
||||
|
@ -225,7 +193,7 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize)
|
|||
iwad->MapInfo = "mapinfo/mindefaults.txt";
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("NAMES"))
|
||||
else if (result == nullptr && sc.Compare("NAMES"))
|
||||
{
|
||||
sc.MustGetStringName("{");
|
||||
mIWadNames.Push(FString());
|
||||
|
@ -233,20 +201,22 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize)
|
|||
{
|
||||
sc.MustGetString();
|
||||
FString wadname = sc.String;
|
||||
#if defined(_WIN32) || defined(__APPLE__) // Turns out Mac OS X is case insensitive.
|
||||
mIWadNames.Push(wadname);
|
||||
#else
|
||||
// check for lowercase, uppercased first letter and full uppercase on Linux etc.
|
||||
wadname.ToLower();
|
||||
mIWadNames.Push(wadname);
|
||||
wadname.LockBuffer()[0] = toupper(wadname[0]);
|
||||
wadname.UnlockBuffer();
|
||||
mIWadNames.Push(wadname);
|
||||
wadname.ToUpper();
|
||||
mIWadNames.Push(wadname);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (result == nullptr && sc.Compare("ORDER"))
|
||||
{
|
||||
sc.MustGetStringName("{");
|
||||
while (!sc.CheckString("}"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
mOrderNames.Push(sc.String);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptError("Unknown keyword '%s'", sc.String);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,7 +226,7 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void FIWadManager::ParseIWadInfos(const char *fn)
|
||||
FIWadManager::FIWadManager(const char *fn)
|
||||
{
|
||||
FResourceFile *resfile = FResourceFile::OpenResourceFile(fn, NULL, true);
|
||||
if (resfile != NULL)
|
||||
|
@ -275,7 +245,7 @@ void FIWadManager::ParseIWadInfos(const char *fn)
|
|||
}
|
||||
delete resfile;
|
||||
}
|
||||
if (mIWadNames.Size() == 0 || mIWads.Size() == 0)
|
||||
if (mIWadNames.Size() == 0 || mIWadInfos.Size() == 0)
|
||||
{
|
||||
I_FatalError("No IWAD definitions found");
|
||||
}
|
||||
|
@ -293,9 +263,25 @@ int FIWadManager::ScanIWAD (const char *iwad)
|
|||
{
|
||||
FResourceFile *iwadfile = FResourceFile::OpenResourceFile(iwad, NULL, true);
|
||||
|
||||
mLumpsFound.Resize(mIWadInfos.Size());
|
||||
|
||||
auto CheckLumpName = [=](const char *name)
|
||||
{
|
||||
for (unsigned i = 0; i< mIWadInfos.Size(); i++)
|
||||
{
|
||||
for (unsigned j = 0; j < mIWadInfos[i].Lumps.Size(); j++)
|
||||
{
|
||||
if (!mIWadInfos[i].Lumps[j].CompareNoCase(name))
|
||||
{
|
||||
mLumpsFound[i] |= (1 << j);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (iwadfile != NULL)
|
||||
{
|
||||
ClearChecks();
|
||||
memset(&mLumpsFound[0], 0, mLumpsFound.Size() * sizeof(mLumpsFound[0]));
|
||||
for(uint32_t ii = 0; ii < iwadfile->LumpCount(); ii++)
|
||||
{
|
||||
FResourceLump *lump = iwadfile->GetLump(ii);
|
||||
|
@ -312,52 +298,171 @@ int FIWadManager::ScanIWAD (const char *iwad)
|
|||
}
|
||||
delete iwadfile;
|
||||
}
|
||||
return GetIWadInfo();
|
||||
for (unsigned i = 0; i< mIWadInfos.Size(); i++)
|
||||
{
|
||||
if (mLumpsFound[i] == (1 << mIWadInfos[i].Lumps.Size()) - 1)
|
||||
{
|
||||
DPrintf(DMSG_NOTIFY, "Identified %s as %s\n", iwad, mIWadInfos[i].Name.GetChars());
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// CheckIWAD
|
||||
// Look for IWAD definition lump
|
||||
//
|
||||
// Tries to find an IWAD from a set of known IWAD names, and checks the
|
||||
// contents of each one found to determine which game it belongs to.
|
||||
// Returns the number of new wads found in this pass (does not count wads
|
||||
// found from a previous call).
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FIWadManager::CheckIWAD (const char *doomwaddir, WadStuff *wads)
|
||||
int FIWadManager::CheckIWADInfo(const char *fn)
|
||||
{
|
||||
const char *slash;
|
||||
int numfound;
|
||||
|
||||
numfound = 0;
|
||||
|
||||
slash = (doomwaddir[0] && doomwaddir[strlen (doomwaddir)-1] != '/') ? "/" : "";
|
||||
|
||||
// Search for a pre-defined IWAD
|
||||
for (unsigned i=0; i< mIWadNames.Size(); i++)
|
||||
FResourceFile *resfile = FResourceFile::OpenResourceFile(fn, NULL, true);
|
||||
if (resfile != NULL)
|
||||
{
|
||||
if (mIWadNames[i].IsNotEmpty() && wads[i].Path.IsEmpty())
|
||||
uint32_t cnt = resfile->LumpCount();
|
||||
for (int i = cnt - 1; i >= 0; i--)
|
||||
{
|
||||
FString iwad;
|
||||
|
||||
iwad.Format ("%s%s%s", doomwaddir, slash, mIWadNames[i].GetChars());
|
||||
FixPathSeperator (iwad);
|
||||
if (FileExists (iwad))
|
||||
FResourceLump *lmp = resfile->GetLump(i);
|
||||
|
||||
if (lmp->Namespace == ns_global && !stricmp(lmp->Name, "IWADINFO"))
|
||||
{
|
||||
wads[i].Type = ScanIWAD (iwad);
|
||||
if (wads[i].Type != -1)
|
||||
// Found one!
|
||||
try
|
||||
{
|
||||
wads[i].Path = iwad;
|
||||
wads[i].Name = mIWads[wads[i].Type].Name;
|
||||
numfound++;
|
||||
FIWADInfo result;
|
||||
ParseIWadInfo(resfile->Filename, (const char*)lmp->CacheLump(), lmp->LumpSize, &result);
|
||||
delete resfile;
|
||||
for (auto &wadinf : mIWadInfos)
|
||||
{
|
||||
if (wadinf.Name == result.Name)
|
||||
{
|
||||
return -1; // do not show the same one twice.
|
||||
}
|
||||
}
|
||||
return mIWadInfos.Push(result);
|
||||
}
|
||||
catch (CRecoverableError &err)
|
||||
{
|
||||
delete resfile;
|
||||
Printf(TEXTCOLOR_RED "%s: %s\nFile has been removed from the list of IWADs\n", fn, err.GetMessage());
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete resfile;
|
||||
Printf(TEXTCOLOR_RED "%s: Unable to find IWADINFO\nFile has been removed from the list of IWADs\n", fn);
|
||||
return -1;
|
||||
}
|
||||
Printf(TEXTCOLOR_RED "%s: Unable to open as resource file.\nFile has been removed from the list of IWADs\n", fn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// CollectSearchPaths
|
||||
//
|
||||
// collect all paths in a local array for easier management
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FIWadManager::CollectSearchPaths()
|
||||
{
|
||||
if (GameConfig->SetSection("IWADSearch.Directories"))
|
||||
{
|
||||
const char *key;
|
||||
const char *value;
|
||||
|
||||
while (GameConfig->NextInSection(key, value))
|
||||
{
|
||||
if (stricmp(key, "Path") == 0)
|
||||
{
|
||||
FString nice = NicePath(value);
|
||||
if (nice.Len() > 0) mSearchPaths.Push(nice);
|
||||
}
|
||||
}
|
||||
}
|
||||
mSearchPaths.Append(I_GetGogPaths());
|
||||
mSearchPaths.Append(I_GetSteamPath());
|
||||
|
||||
return numfound;
|
||||
// Unify and remove trailing slashes
|
||||
for (auto &str : mSearchPaths)
|
||||
{
|
||||
FixPathSeperator(str);
|
||||
if (str[str.Len() - 1] == '/') str.Truncate(str.Len() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// AddIWADCandidates
|
||||
//
|
||||
// scans the given directory and adds all potential IWAD candidates
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FIWadManager::AddIWADCandidates(const char *dir)
|
||||
{
|
||||
void *handle;
|
||||
findstate_t findstate;
|
||||
FStringf slasheddir("%s/", dir);
|
||||
FString findmask = slasheddir + "*.*";
|
||||
if ((handle = I_FindFirst(findmask, &findstate)) != (void *)-1)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (!(I_FindAttr(&findstate) & FA_DIREC))
|
||||
{
|
||||
auto FindName = I_FindName(&findstate);
|
||||
auto p = strrchr(FindName, '.');
|
||||
if (p != nullptr)
|
||||
{
|
||||
// special IWAD extension.
|
||||
if (!stricmp(p, ".iwad") || !stricmp(p, ".ipk3") || !stricmp(p, "ipk7"))
|
||||
{
|
||||
mFoundWads.Push(FFoundWadInfo{ slasheddir + FindName, "", -1 });
|
||||
}
|
||||
}
|
||||
for (auto &name : mIWadNames)
|
||||
{
|
||||
if (!stricmp(name, FindName))
|
||||
{
|
||||
mFoundWads.Push(FFoundWadInfo{ slasheddir + FindName, "", -1 });
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (I_FindNext(handle, &findstate) == 0);
|
||||
I_FindClose(handle);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ValidateIWADs
|
||||
//
|
||||
// validate all found candidates and eliminate the bogus ones.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FIWadManager::ValidateIWADs()
|
||||
{
|
||||
TArray<int> returns;
|
||||
unsigned originalsize = mIWadInfos.Size();
|
||||
for (auto &p : mFoundWads)
|
||||
{
|
||||
int index;
|
||||
auto x = strrchr(p.mFullPath, '.');
|
||||
if (x != nullptr && (!stricmp(x, ".iwad") || !stricmp(x, ".ipk3") || !stricmp(x, "ipk7")))
|
||||
{
|
||||
index = CheckIWADInfo(p.mFullPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
index = ScanIWAD(p.mFullPath);
|
||||
}
|
||||
p.mInfoIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -383,131 +488,138 @@ int FIWadManager::CheckIWAD (const char *doomwaddir, WadStuff *wads)
|
|||
|
||||
static bool havepicked = false;
|
||||
|
||||
int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, const char *zdoom_wad)
|
||||
int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, const char *zdoom_wad, const char *optional_wad)
|
||||
{
|
||||
TArray<WadStuff> wads;
|
||||
TArray<size_t> foundwads;
|
||||
const char *iwadparm = Args->CheckValue ("-iwad");
|
||||
int pickwad;
|
||||
size_t numwads;
|
||||
size_t i;
|
||||
bool iwadparmfound = false;
|
||||
FString custwad;
|
||||
|
||||
wads.Resize(mIWadNames.Size());
|
||||
foundwads.Resize(mIWads.Size());
|
||||
memset(&foundwads[0], 0, foundwads.Size() * sizeof(foundwads[0]));
|
||||
CollectSearchPaths();
|
||||
|
||||
if (iwadparm == NULL && iwad != NULL && *iwad != 0)
|
||||
// Collect all IWADs in the search path
|
||||
for (auto &dir : mSearchPaths)
|
||||
{
|
||||
iwadparm = iwad;
|
||||
AddIWADCandidates(dir);
|
||||
}
|
||||
unsigned numFoundWads = mFoundWads.Size();
|
||||
|
||||
if (iwadparm)
|
||||
{
|
||||
// Check if the given IWAD has an absolute path, in which case the search path will be ignored.
|
||||
custwad = iwadparm;
|
||||
FixPathSeperator (custwad);
|
||||
if (CheckIWAD (custwad, &wads[0]))
|
||||
{ // -iwad parameter was a directory
|
||||
iwadparm = NULL;
|
||||
FixPathSeperator(custwad);
|
||||
DefaultExtension(custwad, ".wad");
|
||||
bool isAbsolute = (custwad[0] == '/');
|
||||
#ifdef WINDOWS
|
||||
isAbsolute |= (custwad.Len() >= 2 && custwad[1] == ':');
|
||||
#endif
|
||||
if (isAbsolute)
|
||||
{
|
||||
if (FileExists(custwad)) mFoundWads.Push({ custwad, "", -1 });
|
||||
}
|
||||
else
|
||||
{
|
||||
DefaultExtension (custwad, ".wad");
|
||||
iwadparm = custwad;
|
||||
mIWadNames[0] = custwad;
|
||||
CheckIWAD ("", &wads[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (iwadparm == NULL || wads[0].Path.IsEmpty() || mIWads[wads[0].Type].Required.IsNotEmpty())
|
||||
{
|
||||
if (GameConfig->SetSection ("IWADSearch.Directories"))
|
||||
{
|
||||
const char *key;
|
||||
const char *value;
|
||||
|
||||
while (GameConfig->NextInSection (key, value))
|
||||
for (auto &dir : mSearchPaths)
|
||||
{
|
||||
if (stricmp (key, "Path") == 0)
|
||||
FStringf fullpath("%s/%s", dir.GetChars(), custwad.GetChars());
|
||||
if (FileExists(fullpath))
|
||||
{
|
||||
FString nice = NicePath(value);
|
||||
FixPathSeperator(nice);
|
||||
CheckIWAD(nice, &wads[0]);
|
||||
mFoundWads.Push({ fullpath, "", -1 });
|
||||
}
|
||||
}
|
||||
}
|
||||
TArray<FString> gog_paths = I_GetGogPaths();
|
||||
for (i = 0; i < gog_paths.Size(); ++i)
|
||||
{
|
||||
CheckIWAD (gog_paths[i], &wads[0]);
|
||||
}
|
||||
TArray<FString> steam_path = I_GetSteamPath();
|
||||
for (i = 0; i < steam_path.Size(); ++i)
|
||||
{
|
||||
CheckIWAD (steam_path[i], &wads[0]);
|
||||
}
|
||||
}
|
||||
// -iwad not found or not specified. Revert back to standard behavior.
|
||||
if (mFoundWads.Size() == numFoundWads) iwadparm = nullptr;
|
||||
|
||||
if (iwadparm != NULL && !wads[0].Path.IsEmpty())
|
||||
{
|
||||
iwadparmfound = true;
|
||||
}
|
||||
// Now check if what got collected actually is an IWAD.
|
||||
ValidateIWADs();
|
||||
|
||||
for (i = numwads = 0; i < mIWadNames.Size(); i++)
|
||||
// Check for required dependencies.
|
||||
for (unsigned i = 0; i < mFoundWads.Size(); i++)
|
||||
{
|
||||
if (!wads[i].Path.IsEmpty())
|
||||
auto infndx = mFoundWads[i].mInfoIndex;
|
||||
if (infndx >= 0)
|
||||
{
|
||||
if (i != numwads)
|
||||
auto &wadinfo = mIWadInfos[infndx];
|
||||
if (wadinfo.Required.IsNotEmpty())
|
||||
{
|
||||
wads[numwads] = wads[i];
|
||||
}
|
||||
foundwads[wads[numwads].Type] = numwads + 1;
|
||||
numwads++;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i=0; i<mIWads.Size(); i++)
|
||||
{
|
||||
if (mIWads[i].Required.IsNotEmpty() && foundwads[i])
|
||||
{
|
||||
bool found = false;
|
||||
// needs to be loaded with another IWAD (HexenDK)
|
||||
for (unsigned j=0; j<mIWads.Size(); j++)
|
||||
{
|
||||
if (!mIWads[i].Required.Compare(mIWads[j].Name))
|
||||
bool found = false;
|
||||
// needs to be loaded with another IWAD (HexenDK)
|
||||
for (unsigned j = 0; j < mFoundWads.Size(); j++)
|
||||
{
|
||||
if (foundwads[j])
|
||||
auto inf2ndx = mFoundWads[j].mInfoIndex;
|
||||
if (inf2ndx >= 0)
|
||||
{
|
||||
found = true;
|
||||
mIWads[i].preload = j;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// The required WAD is not there so this one can't be used and must be deleted from the list
|
||||
if (!found)
|
||||
{
|
||||
size_t kill = foundwads[i];
|
||||
for (size_t j = kill; j < numwads; ++j)
|
||||
{
|
||||
wads[j - 1] = wads[j];
|
||||
}
|
||||
numwads--;
|
||||
foundwads[i] = 0;
|
||||
for (unsigned j = 0; j < foundwads.Size(); ++j)
|
||||
{
|
||||
if (foundwads[j] > kill)
|
||||
{
|
||||
foundwads[j]--;
|
||||
if (!mIWadInfos[infndx].Required.Compare(mIWadInfos[inf2ndx].Name))
|
||||
{
|
||||
mFoundWads[i].mRequiredPath = mFoundWads[j].mFullPath;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The required dependency was not found. Skip this IWAD.
|
||||
if (mFoundWads[i].mRequiredPath.IsEmpty()) mFoundWads[i].mInfoIndex = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
TArray<FFoundWadInfo> picks;
|
||||
if (numFoundWads < mFoundWads.Size())
|
||||
{
|
||||
// We have a -iwad parameter. Pick the first usable IWAD we found through that.
|
||||
for (unsigned i = numFoundWads; i < mFoundWads.Size(); i++)
|
||||
{
|
||||
if (mFoundWads[i].mInfoIndex > 0)
|
||||
{
|
||||
picks.Push(mFoundWads[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (iwad != nullptr && *iwad != 0)
|
||||
{
|
||||
int pickedprio = -1;
|
||||
// scan the list of found IWADs for a matching one for the current PWAD.
|
||||
for (auto &found : mFoundWads)
|
||||
{
|
||||
if (found.mInfoIndex >= 0 && mIWadInfos[found.mInfoIndex].IWadname.CompareNoCase(iwad) == 0 && mIWadInfos[found.mInfoIndex].prio > pickedprio)
|
||||
{
|
||||
picks.Clear();
|
||||
picks.Push(found);
|
||||
pickedprio = mIWadInfos[found.mInfoIndex].prio;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (picks.Size() == 0)
|
||||
{
|
||||
// Now sort what we found and discard all duplicates.
|
||||
for (unsigned i = 0; i < mOrderNames.Size(); i++)
|
||||
{
|
||||
bool picked = false;
|
||||
for (int j = 0; j < (int)mFoundWads.Size(); j++)
|
||||
{
|
||||
if (mFoundWads[j].mInfoIndex >= 0)
|
||||
{
|
||||
if (mIWadInfos[mFoundWads[j].mInfoIndex].Name.Compare(mOrderNames[i]) == 0)
|
||||
{
|
||||
if (!picked)
|
||||
{
|
||||
picked = true;
|
||||
picks.Push(mFoundWads[j]);
|
||||
}
|
||||
mFoundWads.Delete(j--);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// What's left is IWADs with their own IWADINFO. Copy those in order of discovery.
|
||||
for (auto &entry : mFoundWads)
|
||||
{
|
||||
if (entry.mInfoIndex >= 0) picks.Push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (numwads == 0)
|
||||
// If we still haven't found a suitable IWAD let's error out.
|
||||
if (picks.Size() == 0)
|
||||
{
|
||||
I_FatalError ("Cannot find a game IWAD (doom.wad, doom2.wad, heretic.wad, etc.).\n"
|
||||
"Did you install " GAMENAME " properly? You can do either of the following:\n"
|
||||
|
@ -526,38 +638,48 @@ int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad,
|
|||
"iwads to the list beneath [IWADSearch.Directories]");
|
||||
#endif
|
||||
}
|
||||
int pick = 0;
|
||||
|
||||
pickwad = 0;
|
||||
|
||||
if (!iwadparmfound && numwads > 1)
|
||||
// We got more than one so present the IWAD selection box.
|
||||
if (picks.Size() > 1)
|
||||
{
|
||||
int defiwad = 0;
|
||||
|
||||
// Locate the user's prefered IWAD, if it was found.
|
||||
if (defaultiwad[0] != '\0')
|
||||
{
|
||||
for (i = 0; i < numwads; ++i)
|
||||
for (unsigned i = 0; i < picks.Size(); ++i)
|
||||
{
|
||||
FString basename = ExtractFileBase(wads[i].Path);
|
||||
FString &basename = mIWadInfos[picks[i].mInfoIndex].Name;
|
||||
if (stricmp(basename, defaultiwad) == 0)
|
||||
{
|
||||
defiwad = (int)i;
|
||||
pick = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!havepicked) // just use the first IWAD if the restart doesn't have a -iwad parameter. We cannot open the picker in fullscreen mode.
|
||||
if (picks.Size() > 1)
|
||||
{
|
||||
pickwad = I_PickIWad(&wads[0], (int)numwads, queryiwad, defiwad);
|
||||
if (pickwad >= 0)
|
||||
if (!havepicked)
|
||||
{
|
||||
// The newly selected IWAD becomes the new default
|
||||
FString basename = ExtractFileBase(wads[pickwad].Path);
|
||||
defaultiwad = basename;
|
||||
TArray<WadStuff> wads;
|
||||
for (auto & found : picks)
|
||||
{
|
||||
WadStuff stuff;
|
||||
stuff.Name = mIWadInfos[found.mInfoIndex].Name;
|
||||
stuff.Path = ExtractFileBase(found.mFullPath);
|
||||
wads.Push(stuff);
|
||||
}
|
||||
pick = I_PickIWad(&wads[0], (int)wads.Size(), queryiwad, pick);
|
||||
if (pick >= 0)
|
||||
{
|
||||
// The newly selected IWAD becomes the new default
|
||||
defaultiwad = mIWadInfos[picks[pick].mInfoIndex].Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
havepicked = true;
|
||||
}
|
||||
if (pickwad < 0)
|
||||
exit(0);
|
||||
havepicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -565,15 +687,23 @@ int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad,
|
|||
wadfiles.Clear();
|
||||
D_AddFile (wadfiles, zdoom_wad);
|
||||
|
||||
if (mIWads[wads[pickwad].Type].preload >= 0)
|
||||
{
|
||||
D_AddFile (wadfiles, wads[foundwads[mIWads[wads[pickwad].Type].preload]-1].Path);
|
||||
}
|
||||
D_AddFile (wadfiles, wads[pickwad].Path);
|
||||
// [SP] Load non-free assets if available. This must be done before the IWAD.
|
||||
if (D_AddFile(wadfiles, optional_wad))
|
||||
Wads.SetIwadNum(2);
|
||||
else
|
||||
Wads.SetIwadNum(1);
|
||||
|
||||
for (unsigned i=0; i < mIWads[wads[pickwad].Type].Load.Size(); i++)
|
||||
if (picks[pick].mRequiredPath.IsNotEmpty())
|
||||
{
|
||||
long lastslash = wads[pickwad].Path.LastIndexOf ('/');
|
||||
D_AddFile (wadfiles, picks[pick].mRequiredPath);
|
||||
}
|
||||
D_AddFile (wadfiles, picks[pick].mFullPath);
|
||||
|
||||
auto info = mIWadInfos[picks[pick].mInfoIndex];
|
||||
// Load additional resources from the same directory as the IWAD itself.
|
||||
for (unsigned i=0; i < info.Load.Size(); i++)
|
||||
{
|
||||
long lastslash = picks[pick].mFullPath.LastIndexOf ('/');
|
||||
FString path;
|
||||
|
||||
if (lastslash == -1)
|
||||
|
@ -582,13 +712,13 @@ int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad,
|
|||
}
|
||||
else
|
||||
{
|
||||
path = FString (wads[pickwad].Path.GetChars(), lastslash + 1);
|
||||
path = FString (picks[pick].mFullPath.GetChars(), lastslash + 1);
|
||||
}
|
||||
path += mIWads[wads[pickwad].Type].Load[i];
|
||||
path += info.Load[i];
|
||||
D_AddFile (wadfiles, path);
|
||||
|
||||
}
|
||||
return wads[pickwad].Type;
|
||||
return picks[pick].mInfoIndex;
|
||||
}
|
||||
|
||||
|
||||
|
@ -598,11 +728,11 @@ int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad,
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
const FIWADInfo *FIWadManager::FindIWAD(TArray<FString> &wadfiles, const char *iwad, const char *basewad)
|
||||
const FIWADInfo *FIWadManager::FindIWAD(TArray<FString> &wadfiles, const char *iwad, const char *basewad, const char *optionalwad)
|
||||
{
|
||||
int iwadType = IdentifyVersion(wadfiles, iwad, basewad);
|
||||
int iwadType = IdentifyVersion(wadfiles, iwad, basewad, optionalwad);
|
||||
//gameiwad = iwadType;
|
||||
const FIWADInfo *iwad_info = &mIWads[iwadType];
|
||||
const FIWADInfo *iwad_info = &mIWadInfos[iwadType];
|
||||
if (DoomStartupInfo.Name.IsEmpty()) DoomStartupInfo.Name = iwad_info->Name;
|
||||
if (DoomStartupInfo.BkColor == 0 && DoomStartupInfo.FgColor == 0)
|
||||
{
|
||||
|
@ -611,4 +741,4 @@ const FIWADInfo *FIWadManager::FindIWAD(TArray<FString> &wadfiles, const char *i
|
|||
}
|
||||
I_SetIWADInfo();
|
||||
return iwad_info;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -399,19 +399,19 @@ CUSTOM_CVAR (Int, dmflags, 0, CVAR_SERVERINFO)
|
|||
// If nofov is set, force everybody to the arbitrator's FOV.
|
||||
if ((self & DF_NO_FOV) && consoleplayer == Net_Arbitrator)
|
||||
{
|
||||
uint8_t fov;
|
||||
float fov;
|
||||
|
||||
Net_WriteByte (DEM_FOV);
|
||||
|
||||
// If the game is started with DF_NO_FOV set, the arbitrator's
|
||||
// DesiredFOV will not be set when this callback is run, so
|
||||
// be sure not to transmit a 0 FOV.
|
||||
fov = (uint8_t)players[consoleplayer].DesiredFOV;
|
||||
fov = players[consoleplayer].DesiredFOV;
|
||||
if (fov == 0)
|
||||
{
|
||||
fov = 90;
|
||||
}
|
||||
Net_WriteByte (fov);
|
||||
Net_WriteFloat (fov);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -684,8 +684,15 @@ void D_Display ()
|
|||
|
||||
if (viewactive)
|
||||
{
|
||||
R_SetFOV (r_viewpoint, players[consoleplayer].camera && players[consoleplayer].camera->player ?
|
||||
players[consoleplayer].camera->player->FOV : 90.f);
|
||||
DAngle fov = 90.f;
|
||||
AActor *cam = players[consoleplayer].camera;
|
||||
if (cam)
|
||||
{
|
||||
if (cam->player)
|
||||
fov = cam->player->FOV;
|
||||
else fov = cam->CameraFOV;
|
||||
}
|
||||
R_SetFOV(r_viewpoint, fov);
|
||||
}
|
||||
|
||||
// [RH] change the screen mode if needed
|
||||
|
@ -981,6 +988,7 @@ void D_ErrorCleanup ()
|
|||
G_CheckDemoStatus ();
|
||||
Net_ClearBuffers ();
|
||||
G_NewInit ();
|
||||
M_ClearMenus ();
|
||||
singletics = false;
|
||||
playeringame[0] = 1;
|
||||
players[0].playerstate = PST_LIVE;
|
||||
|
@ -1984,9 +1992,9 @@ static FString CheckGameInfo(TArray<FString> & pwads)
|
|||
|
||||
static void SetMapxxFlag()
|
||||
{
|
||||
int lump_name = Wads.CheckNumForName("MAP01", ns_global, FWadCollection::IWAD_FILENUM);
|
||||
int lump_wad = Wads.CheckNumForFullName("maps/map01.wad", FWadCollection::IWAD_FILENUM);
|
||||
int lump_map = Wads.CheckNumForFullName("maps/map01.map", FWadCollection::IWAD_FILENUM);
|
||||
int lump_name = Wads.CheckNumForName("MAP01", ns_global, Wads.GetIwadNum());
|
||||
int lump_wad = Wads.CheckNumForFullName("maps/map01.wad", Wads.GetIwadNum());
|
||||
int lump_map = Wads.CheckNumForFullName("maps/map01.map", Wads.GetIwadNum());
|
||||
|
||||
if (lump_name >= 0 || lump_wad >= 0 || lump_map >= 0) gameinfo.flags |= GI_MAPxx;
|
||||
}
|
||||
|
@ -2331,6 +2339,8 @@ void D_DoomMain (void)
|
|||
}
|
||||
}
|
||||
|
||||
if (!batchrun) Printf(PRINT_LOG, "%s version %s\n", GAMENAME, GetVersionString());
|
||||
|
||||
D_DoomInit();
|
||||
|
||||
// [RH] Make sure zdoom.pk3 is always loaded,
|
||||
|
@ -2342,8 +2352,9 @@ void D_DoomMain (void)
|
|||
}
|
||||
FString basewad = wad;
|
||||
|
||||
iwad_man = new FIWadManager;
|
||||
iwad_man->ParseIWadInfos(basewad);
|
||||
FString optionalwad = BaseFileSearch(OPTIONALWAD, NULL, true);
|
||||
|
||||
iwad_man = new FIWadManager(basewad);
|
||||
|
||||
// Now that we have the IWADINFO, initialize the autoload ini sections.
|
||||
GameConfig->DoAutoloadSetup(iwad_man);
|
||||
|
@ -2373,10 +2384,9 @@ void D_DoomMain (void)
|
|||
|
||||
if (iwad_man == NULL)
|
||||
{
|
||||
iwad_man = new FIWadManager;
|
||||
iwad_man->ParseIWadInfos(basewad);
|
||||
iwad_man = new FIWadManager(basewad);
|
||||
}
|
||||
const FIWADInfo *iwad_info = iwad_man->FindIWAD(allwads, iwad, basewad);
|
||||
const FIWADInfo *iwad_info = iwad_man->FindIWAD(allwads, iwad, basewad, optionalwad);
|
||||
gameinfo.gametype = iwad_info->gametype;
|
||||
gameinfo.flags = iwad_info->flags;
|
||||
gameinfo.ConfigName = iwad_info->Configname;
|
||||
|
|
52
src/d_main.h
52
src/d_main.h
|
@ -70,29 +70,38 @@ extern uint32_t r_renderercaps;
|
|||
|
||||
struct WadStuff
|
||||
{
|
||||
WadStuff() : Type(0) {}
|
||||
|
||||
FString Path;
|
||||
FString Name;
|
||||
int Type;
|
||||
};
|
||||
|
||||
struct FIWADInfo
|
||||
{
|
||||
FString Name; // Title banner text for this IWAD
|
||||
FString Autoname; // Name of autoload ini section for this IWAD
|
||||
FString IWadname; // Default name this game would use - this is for IWAD detection in GAMEINFO.
|
||||
int prio = 0; // selection priority for given IWAD name.
|
||||
FString Configname; // Name of config section for this IWAD
|
||||
FString Required; // Requires another IWAD
|
||||
uint32_t FgColor; // Foreground color for title banner
|
||||
uint32_t BkColor; // Background color for title banner
|
||||
EGameType gametype; // which game are we playing?
|
||||
uint32_t FgColor = 0; // Foreground color for title banner
|
||||
uint32_t BkColor = 0xc0c0c0; // Background color for title banner
|
||||
EGameType gametype = GAME_Doom; // which game are we playing?
|
||||
FString MapInfo; // Base mapinfo to load
|
||||
TArray<FString> Load; // Wads to be loaded with this one.
|
||||
TArray<FString> Lumps; // Lump names for identification
|
||||
int flags;
|
||||
int preload;
|
||||
int flags = 0;
|
||||
};
|
||||
|
||||
FIWADInfo() { flags = 0; preload = -1; FgColor = 0; BkColor= 0xc0c0c0; gametype = GAME_Doom; }
|
||||
struct FFoundWadInfo
|
||||
{
|
||||
FString mFullPath;
|
||||
FString mRequiredPath;
|
||||
int mInfoIndex = -1; // must be an index because of reallocation
|
||||
|
||||
FFoundWadInfo() {}
|
||||
FFoundWadInfo(const FString &s1, const FString &s2, int index)
|
||||
: mFullPath(s1), mRequiredPath(s2), mInfoIndex(index)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct FStartupInfo
|
||||
|
@ -123,28 +132,31 @@ extern FStartupInfo DoomStartupInfo;
|
|||
|
||||
class FIWadManager
|
||||
{
|
||||
TArray<FIWADInfo> mIWads;
|
||||
TArray<FIWADInfo> mIWadInfos;
|
||||
TArray<FString> mIWadNames;
|
||||
TArray<FString> mSearchPaths;
|
||||
TArray<FString> mOrderNames;
|
||||
TArray<FFoundWadInfo> mFoundWads;
|
||||
TArray<int> mLumpsFound;
|
||||
|
||||
void ParseIWadInfo(const char *fn, const char *data, int datasize);
|
||||
void ClearChecks();
|
||||
void CheckLumpName(const char *name);
|
||||
int GetIWadInfo();
|
||||
void ParseIWadInfo(const char *fn, const char *data, int datasize, FIWADInfo *result = nullptr);
|
||||
int ScanIWAD (const char *iwad);
|
||||
int CheckIWAD (const char *doomwaddir, WadStuff *wads);
|
||||
int IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, const char *zdoom_wad);
|
||||
int CheckIWADInfo(const char *iwad);
|
||||
int IdentifyVersion (TArray<FString> &wadfiles, const char *iwad, const char *zdoom_wad, const char *optional_wad);
|
||||
void CollectSearchPaths();
|
||||
void AddIWADCandidates(const char *dir);
|
||||
void ValidateIWADs();
|
||||
public:
|
||||
void ParseIWadInfos(const char *fn);
|
||||
const FIWADInfo *FindIWAD(TArray<FString> &wadfiles, const char *iwad, const char *basewad);
|
||||
FIWadManager(const char *fn);
|
||||
const FIWADInfo *FindIWAD(TArray<FString> &wadfiles, const char *iwad, const char *basewad, const char *optionalwad);
|
||||
const FString *GetAutoname(unsigned int num) const
|
||||
{
|
||||
if (num < mIWads.Size()) return &mIWads[num].Autoname;
|
||||
if (num < mIWadInfos.Size()) return &mIWadInfos[num].Autoname;
|
||||
else return NULL;
|
||||
}
|
||||
int GetIWadFlags(unsigned int num) const
|
||||
{
|
||||
if (num < mIWads.Size()) return mIWads[num].flags;
|
||||
if (num < mIWadInfos.Size()) return mIWadInfos[num].flags;
|
||||
else return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -2049,7 +2049,7 @@ FDynamicBuffer::~FDynamicBuffer ()
|
|||
{
|
||||
if (m_Data)
|
||||
{
|
||||
free (m_Data);
|
||||
M_Free (m_Data);
|
||||
m_Data = NULL;
|
||||
}
|
||||
m_Len = m_BufferLen = 0;
|
||||
|
@ -2465,7 +2465,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player)
|
|||
|
||||
case DEM_FOV:
|
||||
{
|
||||
float newfov = (float)ReadByte (stream);
|
||||
float newfov = ReadFloat (stream);
|
||||
|
||||
if (newfov != players[consoleplayer].DesiredFOV)
|
||||
{
|
||||
|
@ -2485,7 +2485,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player)
|
|||
break;
|
||||
|
||||
case DEM_MYFOV:
|
||||
players[player].DesiredFOV = (float)ReadByte (stream);
|
||||
players[player].DesiredFOV = ReadFloat (stream);
|
||||
break;
|
||||
|
||||
case DEM_RUNSCRIPT:
|
||||
|
@ -2775,6 +2775,8 @@ void Net_SkipCommand (int type, uint8_t **stream)
|
|||
break;
|
||||
|
||||
case DEM_INVUSE:
|
||||
case DEM_FOV:
|
||||
case DEM_MYFOV:
|
||||
skip = 4;
|
||||
break;
|
||||
|
||||
|
@ -2784,8 +2786,6 @@ void Net_SkipCommand (int type, uint8_t **stream)
|
|||
|
||||
case DEM_GENERICCHEAT:
|
||||
case DEM_DROPPLAYER:
|
||||
case DEM_FOV:
|
||||
case DEM_MYFOV:
|
||||
case DEM_ADDCONTROLLER:
|
||||
case DEM_DELCONTROLLER:
|
||||
skip = 1;
|
||||
|
|
|
@ -116,8 +116,8 @@ enum EDemoCommand
|
|||
DEM_UNDONE5, // 24
|
||||
DEM_UNDONE6, // 25
|
||||
DEM_SUMMON, // 26 String: Thing to fabricate
|
||||
DEM_FOV, // 27 Byte: New FOV for all players
|
||||
DEM_MYFOV, // 28 Byte: New FOV for this player
|
||||
DEM_FOV, // 27 Float: New FOV for all players
|
||||
DEM_MYFOV, // 28 Float: New FOV for this player
|
||||
DEM_CHANGEMAP2, // 29 Byte: Position in new map, String: name of new map
|
||||
DEM_UNDONE7, // 30
|
||||
DEM_UNDONE8, // 31
|
||||
|
|
|
@ -562,6 +562,10 @@ void FDecalLib::ParseDecal (FScanner &sc)
|
|||
case DECAL_ANIMATOR:
|
||||
sc.MustGetString ();
|
||||
newdecal.Animator = FindAnimator (sc.String);
|
||||
if (newdecal.Animator == nullptr)
|
||||
{
|
||||
sc.ScriptMessage("Unable to find animator %s", sc.String);
|
||||
}
|
||||
break;
|
||||
|
||||
case DECAL_LOWERDECAL:
|
||||
|
|
|
@ -2910,11 +2910,14 @@ void FParser::SF_MoveCamera(void)
|
|||
|
||||
DAngle targetangle = floatvalue(t_argv[4]);
|
||||
DAngle anglespeed = floatvalue(t_argv[5]);
|
||||
DAngle diffangle = deltaangle(cam->Angles.Yaw, targetangle);
|
||||
|
||||
if (movespeed > 0 && anglespeed == 0.)
|
||||
{
|
||||
if (!finished) targetangle = diffangle * movespeed / movelen;
|
||||
if (!finished)
|
||||
{
|
||||
const DAngle diffangle = targetangle - cam->Angles.Yaw;
|
||||
targetangle = cam->Angles.Yaw + diffangle * movespeed / movelen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2924,6 +2927,7 @@ void FParser::SF_MoveCamera(void)
|
|||
cam->radius = 1 / 8192.;
|
||||
cam->Height = 1 / 8192.;
|
||||
cam->SetOrigin(movepos, true);
|
||||
cam->SetAngle(targetangle, false);
|
||||
t_return.value.i = 1;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -2195,7 +2195,7 @@ static void PutSaveWads (FSerializer &arc)
|
|||
const char *name;
|
||||
|
||||
// Name of IWAD
|
||||
name = Wads.GetWadName (FWadCollection::IWAD_FILENUM);
|
||||
name = Wads.GetWadName (Wads.GetIwadNum());
|
||||
arc.AddString("Game WAD", name);
|
||||
|
||||
// Name of wad the map resides in
|
||||
|
|
|
@ -376,6 +376,7 @@ void FMapInfoParser::ParseGameInfo()
|
|||
GAMEINFOKEY_BOOL(drawreadthis, "drawreadthis")
|
||||
GAMEINFOKEY_BOOL(swapmenu, "swapmenu")
|
||||
GAMEINFOKEY_BOOL(dontcrunchcorpses, "dontcrunchcorpses")
|
||||
GAMEINFOKEY_BOOL(correctprintbold, "correctprintbold")
|
||||
GAMEINFOKEY_BOOL(intermissioncounter, "intermissioncounter")
|
||||
GAMEINFOKEY_BOOL(nightmarefast, "nightmarefast")
|
||||
GAMEINFOKEY_COLOR(dimcolor, "dimcolor")
|
||||
|
|
1
src/gi.h
1
src/gi.h
|
@ -114,6 +114,7 @@ struct gameinfo_t
|
|||
bool nightmarefast;
|
||||
bool swapmenu;
|
||||
bool dontcrunchcorpses;
|
||||
bool correctprintbold;
|
||||
TArray<FName> creditPages;
|
||||
TArray<FName> finalePages;
|
||||
TArray<FName> infoPages;
|
||||
|
|
|
@ -88,13 +88,13 @@ void AdjustSpriteOffsets()
|
|||
for (int i = 0; i < numtex; i++)
|
||||
{
|
||||
if (Wads.GetLumpFile(i) > 1) break; // we are past the IWAD
|
||||
if (Wads.GetLumpNamespace(i) == ns_sprites && Wads.GetLumpFile(i) == FWadCollection::IWAD_FILENUM)
|
||||
if (Wads.GetLumpNamespace(i) == ns_sprites && Wads.GetLumpFile(i) == Wads.GetIwadNum())
|
||||
{
|
||||
char str[9];
|
||||
Wads.GetLumpName(str, i);
|
||||
str[8] = 0;
|
||||
FTextureID texid = TexMan.CheckForTexture(str, FTexture::TEX_Sprite, 0);
|
||||
if (texid.isValid() && Wads.GetLumpFile(TexMan[texid]->SourceLump) > FWadCollection::IWAD_FILENUM)
|
||||
if (texid.isValid() && Wads.GetLumpFile(TexMan[texid]->SourceLump) > Wads.GetIwadNum())
|
||||
{
|
||||
// This texture has been replaced by some PWAD.
|
||||
memcpy(&sprid, str, 4);
|
||||
|
@ -137,9 +137,9 @@ void AdjustSpriteOffsets()
|
|||
if (lumpnum >= 0 && lumpnum < Wads.GetNumLumps())
|
||||
{
|
||||
int wadno = Wads.GetLumpFile(lumpnum);
|
||||
if ((iwadonly && wadno==FWadCollection::IWAD_FILENUM) || (!iwadonly && wadno == ofslumpno))
|
||||
if ((iwadonly && wadno==Wads.GetIwadNum()) || (!iwadonly && wadno == ofslumpno))
|
||||
{
|
||||
if (wadno == FWadCollection::IWAD_FILENUM && !forced && iwadonly)
|
||||
if (wadno == Wads.GetIwadNum() && !forced && iwadonly)
|
||||
{
|
||||
memcpy(&sprid, &tex->Name[0], 4);
|
||||
if (donotprocess.CheckKey(sprid)) continue; // do not alter sprites that only get partially replaced.
|
||||
|
|
|
@ -82,12 +82,10 @@ ADD_STAT(shadowmap)
|
|||
return out;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, gl_shadowmap_quality, 128, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CUSTOM_CVAR(Int, gl_shadowmap_quality, 512, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
switch (self)
|
||||
{
|
||||
case 32:
|
||||
case 64:
|
||||
case 128:
|
||||
case 256:
|
||||
case 512:
|
||||
|
|
|
@ -987,7 +987,7 @@ struct FGLInterface : public FRenderer
|
|||
void WriteSavePic (player_t *player, FileWriter *file, int width, int height) override;
|
||||
void StartSerialize(FSerializer &arc) override;
|
||||
void EndSerialize(FSerializer &arc) override;
|
||||
void RenderTextureView (FCanvasTexture *self, AActor *viewpoint, int fov) override;
|
||||
void RenderTextureView (FCanvasTexture *self, AActor *viewpoint, double fov) override;
|
||||
void PreprocessLevel() override;
|
||||
void CleanLevelData() override;
|
||||
bool RequireGLNodes() override;
|
||||
|
@ -1098,7 +1098,7 @@ void FGLInterface::Init()
|
|||
CVAR(Bool, gl_usefb, false , CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
extern TexFilter_s TexFilter[];
|
||||
|
||||
void FGLInterface::RenderTextureView (FCanvasTexture *tex, AActor *Viewpoint, int FOV)
|
||||
void FGLInterface::RenderTextureView (FCanvasTexture *tex, AActor *Viewpoint, double FOV)
|
||||
{
|
||||
FMaterial * gltex = FMaterial::ValidateTexture(tex, false);
|
||||
|
||||
|
|
|
@ -321,6 +321,12 @@ void GLSprite::Draw(int pass)
|
|||
}
|
||||
else if (modelframe == nullptr)
|
||||
{
|
||||
int tm, sb, db, be;
|
||||
|
||||
// This still needs to set the texture mode. As blend mode it will always use GL_ONE/GL_ZERO
|
||||
gl_GetRenderStyle(RenderStyle, false, false, &tm, &sb, &db, &be);
|
||||
gl_RenderState.SetTextureMode(tm);
|
||||
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(-1.0f, -128.0f);
|
||||
}
|
||||
|
@ -685,7 +691,7 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal)
|
|||
|
||||
// check renderrequired vs ~r_rendercaps, if anything matches we don't support that feature,
|
||||
// check renderhidden vs r_rendercaps, if anything matches we do support that feature and should hide it.
|
||||
if (!r_debug_disable_vis_filter && (!!(thing->RenderRequired & ~r_renderercaps)) ||
|
||||
if ((!r_debug_disable_vis_filter && !!(thing->RenderRequired & ~r_renderercaps)) ||
|
||||
(!!(thing->RenderHidden & r_renderercaps)))
|
||||
return;
|
||||
|
||||
|
@ -1301,4 +1307,4 @@ void GLSceneDrawer::RenderActorsInPortal(FGLLinePortal *glport)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "gl/gl_functions.h"
|
||||
#include "g_level.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "actorinlines.h"
|
||||
|
||||
#include "gl/system/gl_cvars.h"
|
||||
#include "gl/renderer/gl_renderer.h"
|
||||
|
@ -179,6 +180,13 @@ void BSPWalkCircle(float x, float y, float radiusSquared, const Callback &callba
|
|||
|
||||
void gl_SetDynModelLight(AActor *self, bool hudmodel)
|
||||
{
|
||||
// Legacy and deferred render paths gets the old flat model light
|
||||
if (gl.lightmethod != LM_DIRECT)
|
||||
{
|
||||
gl_SetDynSpriteLight(self, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
modellightdata.Clear();
|
||||
|
||||
if (self)
|
||||
|
|
|
@ -43,6 +43,7 @@ static TArray<FString> m_Extensions;
|
|||
RenderContext gl;
|
||||
|
||||
EXTERN_CVAR(Bool, gl_legacy_mode)
|
||||
extern int currentrenderer;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -207,7 +208,8 @@ void gl_LoadExtensions()
|
|||
|
||||
// The minimum requirement for the modern render path is GL 3.3.
|
||||
// Although some GL 3.1 or 3.2 solutions may theoretically work they are usually too broken or too slow.
|
||||
if (gl_version < 3.3f)
|
||||
// unless, of course, we're simply using this as a software backend...
|
||||
if ((gl_version < 3.3f && (currentrenderer==1)) || gl_version < 3.0f)
|
||||
{
|
||||
gl.legacyMode = true;
|
||||
gl.lightmethod = LM_LEGACY;
|
||||
|
|
|
@ -93,7 +93,6 @@ EXTERN_CVAR(Float, Gamma)
|
|||
EXTERN_CVAR(Bool, vid_vsync)
|
||||
EXTERN_CVAR(Float, transsouls)
|
||||
EXTERN_CVAR(Int, vid_refreshrate)
|
||||
EXTERN_CVAR(Bool, gl_legacy_mode)
|
||||
|
||||
#ifdef WIN32
|
||||
extern cycle_t BlitCycles;
|
||||
|
@ -199,15 +198,6 @@ OpenGLSWFrameBuffer::OpenGLSWFrameBuffer(void *hMonitor, int width, int height,
|
|||
const char *glversion = (const char*)glGetString(GL_VERSION);
|
||||
bool isGLES = (glversion && strlen(glversion) > 10 && memcmp(glversion, "OpenGL ES ", 10) == 0);
|
||||
|
||||
UCVarValue value;
|
||||
// GL 3.0 is mostly broken on MESA drivers which really are the only relevant case here that doesn't fulfill the requirements based on version number alone.
|
||||
#ifdef _WIN32
|
||||
value.Bool = !ogl_IsVersionGEQ(3, 0);
|
||||
#else
|
||||
value.Bool = !ogl_IsVersionGEQ(3, 1);
|
||||
#endif
|
||||
gl_legacy_mode.ForceSet (value, CVAR_Bool);
|
||||
|
||||
if (!isGLES && ogl_IsVersionGEQ(3, 0) == 0)
|
||||
{
|
||||
Printf("OpenGL acceleration requires at least OpenGL 3.0. No Acceleration will be used.\n");
|
||||
|
|
|
@ -614,7 +614,7 @@ void gl_ParseBrightmap(FScanner &sc, int deflump)
|
|||
|
||||
if (lumpnum != -1)
|
||||
{
|
||||
if (iwad && Wads.GetLumpFile(lumpnum) <= FWadCollection::IWAD_FILENUM) useme = true;
|
||||
if (iwad && Wads.GetLumpFile(lumpnum) <= Wads.GetIwadNum()) useme = true;
|
||||
if (thiswad && Wads.GetLumpFile(lumpnum) == deflump) useme = true;
|
||||
}
|
||||
if (!useme) return;
|
||||
|
|
|
@ -213,7 +213,7 @@ void FSavegameManager::ReadSaveStrings()
|
|||
// old, incompatible savegame. List as not usable.
|
||||
oldVer = true;
|
||||
}
|
||||
else if (iwad.CompareNoCase(Wads.GetWadName(FWadCollection::IWAD_FILENUM)) == 0)
|
||||
else if (iwad.CompareNoCase(Wads.GetWadName(Wads.GetIwadNum())) == 0)
|
||||
{
|
||||
missing = !G_CheckSaveGameWads(arc, false);
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
CVAR (Float, mouse_sensitivity, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, show_messages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, show_obituaries, true, CVAR_ARCHIVE)
|
||||
CVAR(Bool, m_showinputgrid, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR (Int, m_showinputgrid, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Bool, m_blockcontrollers, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
|
||||
|
|
|
@ -1014,7 +1014,7 @@ void M_ParseMenuDefs()
|
|||
atterm( DeinitMenus);
|
||||
DeinitMenus();
|
||||
|
||||
int IWADMenu = Wads.CheckNumForName("MENUDEF", ns_global, FWadCollection::IWAD_FILENUM);
|
||||
int IWADMenu = Wads.CheckNumForName("MENUDEF", ns_global, Wads.GetIwadNum());
|
||||
|
||||
while ((lump = Wads.FindLump ("MENUDEF", &lastlump)) != -1)
|
||||
{
|
||||
|
@ -1386,6 +1386,7 @@ static void InitMusicMenus()
|
|||
DMenuDescriptor **gusmenu = MenuDescriptors.CheckKey("GusConfigMenu");
|
||||
DMenuDescriptor **timiditymenu = MenuDescriptors.CheckKey("TimidityExeMenu");
|
||||
DMenuDescriptor **wildmidimenu = MenuDescriptors.CheckKey("WildMidiConfigMenu");
|
||||
DMenuDescriptor **timiditycfgmenu = MenuDescriptors.CheckKey("TimidityConfigMenu");
|
||||
DMenuDescriptor **fluidmenu = MenuDescriptors.CheckKey("FluidPatchsetMenu");
|
||||
|
||||
const char *key, *value;
|
||||
|
@ -1426,6 +1427,11 @@ static void InitMusicMenus()
|
|||
auto it = CreateOptionMenuItemCommand(key, FStringf("wildmidi_config %s", NicePath(value).GetChars()), true);
|
||||
static_cast<DOptionMenuDescriptor*>(*wildmidimenu)->mItems.Push(it);
|
||||
}
|
||||
if (timiditycfgmenu != nullptr)
|
||||
{
|
||||
auto it = CreateOptionMenuItemCommand(key, FStringf("timidity_config \"%s\"", NicePath(value).GetChars()), true);
|
||||
static_cast<DOptionMenuDescriptor*>(*timiditycfgmenu)->mItems.Push(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1437,6 +1443,8 @@ static void InitMusicMenus()
|
|||
if (it != nullptr) d->mItems.Delete(d->mItems.Find(it));
|
||||
it = d->GetItem("WildMidiConfigMenu");
|
||||
if (it != nullptr) d->mItems.Delete(d->mItems.Find(it));
|
||||
it = d->GetItem("TimidityConfigMenu");
|
||||
if (it != nullptr) d->mItems.Delete(d->mItems.Find(it));
|
||||
}
|
||||
#ifdef _WIN32 // Different Timidity paths only make sense if they can be stored in arbitrary paths with local configs (i.e. not if things are done the Linux way)
|
||||
if (GameConfig->SetSection("TimidityExes"))
|
||||
|
|
|
@ -876,8 +876,7 @@ void P_Spawn3DFloors (void)
|
|||
line.args[4]=0;
|
||||
}
|
||||
}
|
||||
if (line.args[0] != 0)
|
||||
P_Set3DFloor(&line, line.args[1]&~8, line.args[2], line.args[3]);
|
||||
P_Set3DFloor(&line, line.args[1]&~8, line.args[2], line.args[3]);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -1843,7 +1843,9 @@ static bool DoUseInv (AActor *actor, PClassActor *info)
|
|||
AInventory *item = actor->FindInventory (info);
|
||||
if (item != NULL)
|
||||
{
|
||||
if (actor->player == NULL)
|
||||
player_t* const player = actor->player;
|
||||
|
||||
if (nullptr == player)
|
||||
{
|
||||
return actor->UseInventory(item);
|
||||
}
|
||||
|
@ -1853,10 +1855,10 @@ static bool DoUseInv (AActor *actor, PClassActor *info)
|
|||
bool res;
|
||||
|
||||
// Bypass CF_TOTALLYFROZEN
|
||||
cheats = actor->player->cheats;
|
||||
actor->player->cheats &= ~CF_TOTALLYFROZEN;
|
||||
cheats = player->cheats;
|
||||
player->cheats &= ~CF_TOTALLYFROZEN;
|
||||
res = actor->UseInventory(item);
|
||||
actor->player->cheats |= (cheats & CF_TOTALLYFROZEN);
|
||||
player->cheats |= (cheats & CF_TOTALLYFROZEN);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
@ -3437,7 +3439,7 @@ void FBehavior::StartTypedScripts (uint16_t type, AActor *activator, bool always
|
|||
{
|
||||
DLevelScript *runningScript = P_GetScriptGoing (activator, NULL, ptr->Number,
|
||||
ptr, this, &arg1, 1, always ? ACS_ALWAYS : 0);
|
||||
if (runNow)
|
||||
if (nullptr != runningScript && runNow)
|
||||
{
|
||||
runningScript->RunScript ();
|
||||
}
|
||||
|
@ -8765,7 +8767,10 @@ scriptwait:
|
|||
if (pcd == PCD_ENDPRINTBOLD || screen == NULL ||
|
||||
screen->CheckLocalView (consoleplayer))
|
||||
{
|
||||
C_MidPrint (activefont, work);
|
||||
if (pcd == PCD_ENDPRINTBOLD && (gameinfo.correctprintbold || (level.flags2 & LEVEL2_HEXENHACK)))
|
||||
C_MidPrintBold(activefont, work);
|
||||
else
|
||||
C_MidPrint (activefont, work);
|
||||
}
|
||||
STRINGBUILDER_FINISH(work);
|
||||
}
|
||||
|
|
|
@ -979,6 +979,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_StopSound)
|
|||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SoundVolume)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_INT(channel);
|
||||
PARAM_FLOAT(volume);
|
||||
S_ChangeSoundVolume(self, channel, static_cast<float>(volume));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// These come from a time when DECORATE constants did not exist yet and
|
||||
|
@ -5904,9 +5913,9 @@ static void DoKill(AActor *killtarget, AActor *inflictor, AActor *source, FName
|
|||
{
|
||||
int dmgFlags = DMG_NO_ARMOR | DMG_NO_FACTOR;
|
||||
|
||||
if (KILS_FOILINVUL)
|
||||
if (flags & KILS_FOILINVUL)
|
||||
dmgFlags |= DMG_FOILINVUL;
|
||||
if (KILS_FOILBUDDHA)
|
||||
if (flags & KILS_FOILBUDDHA)
|
||||
dmgFlags |= DMG_FOILBUDDHA;
|
||||
|
||||
if ((killtarget->flags & MF_MISSILE) && (flags & KILS_KILLMISSILES))
|
||||
|
|
|
@ -36,6 +36,7 @@ struct FCheckPosition
|
|||
TMap<AActor*, bool> LastRipped;
|
||||
bool DoRipping;
|
||||
bool portalstep;
|
||||
int portalgroup;
|
||||
|
||||
int PushTime;
|
||||
|
||||
|
|
|
@ -161,6 +161,7 @@ DEFINE_FIELD_X(FCheckPosition, FCheckPosition, ceilingline);
|
|||
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, stepthing);
|
||||
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, DoRipping);
|
||||
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, portalstep);
|
||||
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, portalgroup);
|
||||
DEFINE_FIELD_X(FCheckPosition, FCheckPosition, PushTime);
|
||||
|
||||
//==========================================================================
|
||||
|
@ -288,6 +289,7 @@ static bool PIT_FindFloorCeiling(FMultiBlockLinesIterator &mit, FMultiBlockLines
|
|||
}
|
||||
}
|
||||
|
||||
// If we are stepping through a portal the line's opening must be checked, regardless of the NOFLOOR flag
|
||||
if (!(flags & FFCF_NOFLOOR))
|
||||
{
|
||||
if (open.bottom > tmf.floorz)
|
||||
|
@ -905,6 +907,7 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
|
|||
tm.floorpic = cres.line->sidedef[0]->GetTexture(side_t::mid);
|
||||
tm.floorterrain = 0;
|
||||
tm.portalstep = true;
|
||||
tm.portalgroup = cres.line->frontsector->GetOppositePortalGroup(sector_t::ceiling);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -999,6 +1002,7 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
|
|||
{
|
||||
// Actor is stepping through a portal.
|
||||
tm.portalstep = true;
|
||||
tm.portalgroup = tm.thing->Sector->GetOppositePortalGroup(sector_t::ceiling);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1051,7 +1055,8 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
|
|||
}
|
||||
}
|
||||
|
||||
if (!(cres.portalflags & FFCF_NOFLOOR))
|
||||
// If we are stepping through a portal the line's opening must be checked, regardless of the NOFLOOR flag
|
||||
if (!(cres.portalflags & FFCF_NOFLOOR) || (tm.portalstep && open.bottomsec->PortalGroup == tm.portalgroup))
|
||||
{
|
||||
if (open.bottom > tm.floorz)
|
||||
{
|
||||
|
@ -6699,7 +6704,8 @@ bool P_ActivateThingSpecial(AActor * thing, AActor * trigger, bool death)
|
|||
false, thing->args[0], thing->args[1], thing->args[2], thing->args[3], thing->args[4]);
|
||||
|
||||
// Clears the special if it was run on thing's death or if flag is set.
|
||||
if (death || (thing->activationtype & THINGSPEC_ClearSpecial && res)) thing->special = 0;
|
||||
// Note that Hexen originally did not clear the special which some original maps depend on (e.g. the bell in HEXDD.)
|
||||
if ((death && !(level.flags2 & LEVEL2_HEXENHACK)) || (thing->activationtype & THINGSPEC_ClearSpecial && res)) thing->special = 0;
|
||||
}
|
||||
|
||||
// Returns the result
|
||||
|
|
|
@ -346,6 +346,7 @@ DEFINE_FIELD(AActor, Conversation)
|
|||
DEFINE_FIELD(AActor, DecalGenerator)
|
||||
DEFINE_FIELD(AActor, fountaincolor)
|
||||
DEFINE_FIELD(AActor, CameraHeight)
|
||||
DEFINE_FIELD(AActor, CameraFOV)
|
||||
DEFINE_FIELD(AActor, RadiusDamageFactor)
|
||||
DEFINE_FIELD(AActor, SelfDamageFactor)
|
||||
DEFINE_FIELD(AActor, StealthAlpha)
|
||||
|
@ -520,6 +521,7 @@ void AActor::Serialize(FSerializer &arc)
|
|||
A("spriterotation", SpriteRotation)
|
||||
("alternative", alternative)
|
||||
A("cameraheight", CameraHeight)
|
||||
A("camerafov", CameraFOV)
|
||||
A("tag", Tag)
|
||||
A("visiblestartangle",VisibleStartAngle)
|
||||
A("visibleendangle",VisibleEndAngle)
|
||||
|
@ -4036,6 +4038,14 @@ void AActor::CheckPortalTransition(bool islinked)
|
|||
if (islinked && moved) LinkToWorld(&ctx);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, CheckPortalTransition)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_BOOL_DEF(linked);
|
||||
self->CheckPortalTransition(linked);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// P_MobjThinker
|
||||
//
|
||||
|
@ -4069,10 +4079,6 @@ void AActor::Tick ()
|
|||
return;
|
||||
}
|
||||
|
||||
// This is necessary to properly interpolate movement outside this function
|
||||
// like from an ActorMover
|
||||
ClearInterpolation();
|
||||
|
||||
if (flags5 & MF5_NOINTERACTION)
|
||||
{
|
||||
// only do the minimally necessary things here to save time:
|
||||
|
@ -4107,18 +4113,22 @@ void AActor::Tick ()
|
|||
}
|
||||
else
|
||||
{
|
||||
AInventory * item = Inventory;
|
||||
|
||||
// Handle powerup effects here so that the order is controlled
|
||||
// by the order in the inventory, not the order in the thinker table
|
||||
while (item != NULL && item->Owner == this)
|
||||
if (!player || !(player->cheats & CF_PREDICTING))
|
||||
{
|
||||
IFVIRTUALPTR(item, AInventory, DoEffect)
|
||||
// Handle powerup effects here so that the order is controlled
|
||||
// by the order in the inventory, not the order in the thinker table
|
||||
AInventory *item = Inventory;
|
||||
|
||||
while (item != NULL && item->Owner == this)
|
||||
{
|
||||
VMValue params[1] = { item };
|
||||
VMCall(func, params, 1, nullptr, 0);
|
||||
IFVIRTUALPTR(item, AInventory, DoEffect)
|
||||
{
|
||||
VMValue params[1] = { item };
|
||||
VMCall(func, params, 1, nullptr, 0);
|
||||
}
|
||||
item = item->Inventory;
|
||||
}
|
||||
item = item->Inventory;
|
||||
}
|
||||
|
||||
if (flags & MF_UNMORPHED)
|
||||
|
@ -6741,6 +6751,7 @@ bool P_CheckMissileSpawn (AActor* th, double maxdist)
|
|||
|
||||
newpos = th->Vec3Offset(newpos);
|
||||
th->SetXYZ(newpos);
|
||||
th->Sector = P_PointInSector(th->Pos());
|
||||
|
||||
FCheckPosition tm(!!(th->flags2 & MF2_RIP));
|
||||
|
||||
|
|
|
@ -236,7 +236,7 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in)
|
|||
|
||||
FLinePortal *lport = li->getPortal();
|
||||
|
||||
if (open.range == 0 && open.portalflags == 0 && (lport == NULL || lport->mType != PORTT_LINKED)) // quick test for totally closed doors (must be delayed if portal checks are needed, though)
|
||||
if (open.range == 0 && open.portalflags == 0 && (lport == nullptr || lport->mType != PORTT_LINKED)) // quick test for totally closed doors (must be delayed if portal checks are needed, though)
|
||||
return false; // stop
|
||||
|
||||
if (in->frac == 0)
|
||||
|
@ -284,7 +284,7 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in)
|
|||
portals.Push({ in->frac, topslope, bottomslope, sector_t::floor, backsec->GetOppositePortalGroup(sector_t::floor) });
|
||||
}
|
||||
}
|
||||
if (lport)
|
||||
if (lport != nullptr && lport->mDestination != nullptr)
|
||||
{
|
||||
portals.Push({ in->frac, topslope, bottomslope, portaldir, lport->mDestination->frontsector->PortalGroup });
|
||||
return false;
|
||||
|
|
|
@ -596,12 +596,22 @@ void P_GiveSecret(AActor *actor, bool printmessage, bool playsound, int sectornu
|
|||
DEFINE_ACTION_FUNCTION(AActor, GiveSecret)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_BOOL(printmessage);
|
||||
PARAM_BOOL(playsound);
|
||||
PARAM_BOOL_DEF(printmessage);
|
||||
PARAM_BOOL_DEF(playsound);
|
||||
P_GiveSecret(self, printmessage, playsound, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FLevelLocals, GiveSecret)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_OBJECT(activator, AActor);
|
||||
PARAM_BOOL_DEF(printmessage);
|
||||
PARAM_BOOL_DEF(playsound);
|
||||
P_GiveSecret(activator, printmessage, playsound, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// P_PlayerOnSpecialFlat
|
||||
|
|
|
@ -154,7 +154,7 @@ void FStateLabels::Destroy ()
|
|||
if (Labels[i].Children != NULL)
|
||||
{
|
||||
Labels[i].Children->Destroy();
|
||||
free(Labels[i].Children); // These are malloc'd, not new'd!
|
||||
M_Free(Labels[i].Children); // These are malloc'd, not new'd!
|
||||
Labels[i].Children = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -336,7 +336,7 @@ static bool VerifyJumpTarget(PClassActor *cls, FState *CallingState, int index)
|
|||
|
||||
FState *FStateLabelStorage::GetState(int pos, PClassActor *cls, bool exact)
|
||||
{
|
||||
if (pos > 0x10000000)
|
||||
if (pos >= 0x10000000)
|
||||
{
|
||||
return cls? cls->FindState(ENamedName(pos - 0x10000000)) : nullptr;
|
||||
}
|
||||
|
@ -1142,4 +1142,4 @@ DEFINE_ACTION_FUNCTION(FState, ValidateSpriteFrame)
|
|||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FState);
|
||||
ACTION_RETURN_BOOL(self->Frame < sprites[self->sprite].numframes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "p_spec.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "events.h"
|
||||
#include "actorinlines.h"
|
||||
|
||||
extern gamestate_t wipegamestate;
|
||||
|
||||
|
@ -119,6 +120,15 @@ void P_Ticker (void)
|
|||
P_ResetSightCounters (false);
|
||||
R_ClearInterpolationPath();
|
||||
|
||||
// Reset all actor interpolations for all actors before the current thinking turn so that indirect actor movement gets properly interpolated.
|
||||
TThinkerIterator<AActor> it;
|
||||
AActor *ac;
|
||||
|
||||
while ((ac = it.Next()))
|
||||
{
|
||||
ac->ClearInterpolation();
|
||||
}
|
||||
|
||||
// Since things will be moving, it's okay to interpolate them in the renderer.
|
||||
r_NoInterpolate = false;
|
||||
|
||||
|
|
|
@ -614,7 +614,7 @@ void player_t::SetFOV(float fov)
|
|||
{
|
||||
Net_WriteByte(DEM_MYFOV);
|
||||
}
|
||||
Net_WriteByte((uint8_t)clamp<float>(fov, 5.f, 179.f));
|
||||
Net_WriteFloat(clamp<float>(fov, 5.f, 179.f));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -962,7 +962,7 @@ void APlayerPawn::BeginPlay ()
|
|||
int wadnorm = Wads.GetLumpFile(spritenorm);
|
||||
int wadcrouch = Wads.GetLumpFile(spritenorm);
|
||||
|
||||
if (wadnorm > FWadCollection::IWAD_FILENUM && wadcrouch <= FWadCollection::IWAD_FILENUM)
|
||||
if (wadnorm > Wads.GetIwadNum() && wadcrouch <= Wads.GetIwadNum())
|
||||
{
|
||||
// Question: Add an option / disable crouching or do what?
|
||||
crouchsprite = 0;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Triangle drawers
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -38,13 +38,13 @@
|
|||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolySubsectorGBuffer *PolySubsectorGBuffer::Instance()
|
||||
PolyZBuffer *PolyZBuffer::Instance()
|
||||
{
|
||||
static PolySubsectorGBuffer buffer;
|
||||
static PolyZBuffer buffer;
|
||||
return &buffer;
|
||||
}
|
||||
|
||||
void PolySubsectorGBuffer::Resize(int newwidth, int newheight)
|
||||
void PolyZBuffer::Resize(int newwidth, int newheight)
|
||||
{
|
||||
width = newwidth;
|
||||
height = newheight;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Frame buffers
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -26,21 +26,21 @@
|
|||
|
||||
struct TriVertex;
|
||||
|
||||
class PolySubsectorGBuffer
|
||||
class PolyZBuffer
|
||||
{
|
||||
public:
|
||||
static PolySubsectorGBuffer *Instance();
|
||||
static PolyZBuffer *Instance();
|
||||
void Resize(int newwidth, int newheight);
|
||||
int Width() const { return width; }
|
||||
int Height() const { return height; }
|
||||
int BlockWidth() const { return (width + 7) / 8; }
|
||||
int BlockHeight() const { return (height + 7) / 8; }
|
||||
uint32_t *Values() { return values.data(); }
|
||||
float *Values() { return values.data(); }
|
||||
|
||||
private:
|
||||
int width;
|
||||
int height;
|
||||
std::vector<uint32_t> values;
|
||||
std::vector<float> values;
|
||||
};
|
||||
|
||||
class PolyStencilBuffer
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Triangle drawers
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -36,14 +36,7 @@
|
|||
#include "swrenderer/r_swcolormaps.h"
|
||||
#include "poly_draw_args.h"
|
||||
#include "swrenderer/viewport/r_viewport.h"
|
||||
|
||||
void PolyDrawArgs::SetClipPlane(const PolyClipPlane &plane)
|
||||
{
|
||||
mClipPlane[0] = plane.A;
|
||||
mClipPlane[1] = plane.B;
|
||||
mClipPlane[2] = plane.C;
|
||||
mClipPlane[3] = plane.D;
|
||||
}
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
|
||||
void PolyDrawArgs::SetTexture(const uint8_t *texels, int width, int height)
|
||||
{
|
||||
|
@ -133,12 +126,12 @@ void PolyDrawArgs::SetColor(uint32_t bgra, uint8_t palindex)
|
|||
}
|
||||
}
|
||||
|
||||
void PolyDrawArgs::DrawArray(const TriVertex *vertices, int vcount, PolyDrawMode mode)
|
||||
void PolyDrawArgs::DrawArray(PolyRenderThread *thread, const TriVertex *vertices, int vcount, PolyDrawMode mode)
|
||||
{
|
||||
mVertices = vertices;
|
||||
mVertexCount = vcount;
|
||||
mDrawMode = mode;
|
||||
PolyRenderer::Instance()->DrawQueue->Push<DrawPolyTrianglesCommand>(*this, PolyTriangleDrawer::is_mirror());
|
||||
thread->DrawQueue->Push<DrawPolyTrianglesCommand>(*this, PolyTriangleDrawer::is_mirror());
|
||||
}
|
||||
|
||||
void PolyDrawArgs::SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FTexture *tex, bool fullbright)
|
||||
|
@ -281,7 +274,7 @@ void RectDrawArgs::SetColor(uint32_t bgra, uint8_t palindex)
|
|||
}
|
||||
}
|
||||
|
||||
void RectDrawArgs::Draw(double x0, double x1, double y0, double y1, double u0, double u1, double v0, double v1)
|
||||
void RectDrawArgs::Draw(PolyRenderThread *thread, double x0, double x1, double y0, double y1, double u0, double u1, double v0, double v1)
|
||||
{
|
||||
mX0 = (float)x0;
|
||||
mX1 = (float)x1;
|
||||
|
@ -291,7 +284,7 @@ void RectDrawArgs::Draw(double x0, double x1, double y0, double y1, double u0, d
|
|||
mU1 = (float)u1;
|
||||
mV0 = (float)v0;
|
||||
mV1 = (float)v1;
|
||||
PolyRenderer::Instance()->DrawQueue->Push<DrawRectCommand>(*this);
|
||||
thread->DrawQueue->Push<DrawRectCommand>(*this);
|
||||
}
|
||||
|
||||
void RectDrawArgs::SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FTexture *tex, bool fullbright)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Triangle drawers
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -26,6 +26,7 @@
|
|||
#include "r_data/colormaps.h"
|
||||
#include "screen_triangle.h"
|
||||
|
||||
class PolyRenderThread;
|
||||
class FTexture;
|
||||
struct TriMatrix;
|
||||
|
||||
|
@ -48,26 +49,25 @@ public:
|
|||
class PolyDrawArgs
|
||||
{
|
||||
public:
|
||||
void SetClipPlane(const PolyClipPlane &plane);
|
||||
void SetClipPlane(int index, const PolyClipPlane &plane) { mClipPlane[index] = plane; }
|
||||
void SetTexture(const uint8_t *texels, int width, int height);
|
||||
void SetTexture(FTexture *texture);
|
||||
void SetTexture(FTexture *texture, uint32_t translationID, bool forcePal = false);
|
||||
void SetLight(FSWColormap *basecolormap, uint32_t lightlevel, double globVis, bool fixed);
|
||||
void SetSubsectorDepth(uint32_t subsectorDepth) { mSubsectorDepth = subsectorDepth; }
|
||||
void SetSubsectorDepthTest(bool enable) { mSubsectorTest = enable; }
|
||||
void SetDepthTest(bool enable) { mDepthTest = enable; }
|
||||
void SetStencilTestValue(uint8_t stencilTestValue) { mStencilTestValue = stencilTestValue; }
|
||||
void SetWriteColor(bool enable) { mWriteColor = enable; }
|
||||
void SetWriteStencil(bool enable, uint8_t stencilWriteValue = 0) { mWriteStencil = enable; mStencilWriteValue = stencilWriteValue; }
|
||||
void SetWriteSubsectorDepth(bool enable) { mWriteSubsector = enable; }
|
||||
void SetWriteDepth(bool enable) { mWriteDepth = enable; }
|
||||
void SetFaceCullCCW(bool counterclockwise) { mFaceCullCCW = counterclockwise; }
|
||||
void SetStyle(TriBlendMode blendmode, double srcalpha = 1.0, double destalpha = 1.0) { mBlendMode = blendmode; mSrcAlpha = (uint32_t)(srcalpha * 256.0 + 0.5); mDestAlpha = (uint32_t)(destalpha * 256.0 + 0.5); }
|
||||
void SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FTexture *texture, bool fullbright);
|
||||
void SetTransform(const TriMatrix *objectToClip) { mObjectToClip = objectToClip; }
|
||||
void SetColor(uint32_t bgra, uint8_t palindex);
|
||||
void DrawArray(const TriVertex *vertices, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles);
|
||||
void DrawArray(PolyRenderThread *thread, const TriVertex *vertices, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles);
|
||||
|
||||
const TriMatrix *ObjectToClip() const { return mObjectToClip; }
|
||||
const float *ClipPlane() const { return mClipPlane; }
|
||||
const PolyClipPlane &ClipPlane(int index) const { return mClipPlane[index]; }
|
||||
|
||||
const TriVertex *Vertices() const { return mVertices; }
|
||||
int VertexCount() const { return mVertexCount; }
|
||||
|
@ -85,9 +85,8 @@ public:
|
|||
uint8_t StencilTestValue() const { return mStencilTestValue; }
|
||||
uint8_t StencilWriteValue() const { return mStencilWriteValue; }
|
||||
|
||||
bool SubsectorTest() const { return mSubsectorTest; }
|
||||
bool WriteSubsector() const { return mWriteSubsector; }
|
||||
uint32_t SubsectorDepth() const { return mSubsectorDepth; }
|
||||
bool DepthTest() const { return mDepthTest; }
|
||||
bool WriteDepth() const { return mWriteDepth; }
|
||||
|
||||
TriBlendMode BlendMode() const { return mBlendMode; }
|
||||
uint32_t Color() const { return mColor; }
|
||||
|
@ -117,10 +116,10 @@ private:
|
|||
int mVertexCount = 0;
|
||||
PolyDrawMode mDrawMode = PolyDrawMode::Triangles;
|
||||
bool mFaceCullCCW = false;
|
||||
bool mSubsectorTest = false;
|
||||
bool mDepthTest = false;
|
||||
bool mWriteStencil = true;
|
||||
bool mWriteColor = true;
|
||||
bool mWriteSubsector = true;
|
||||
bool mWriteDepth = true;
|
||||
const uint8_t *mTexturePixels = nullptr;
|
||||
int mTextureWidth = 0;
|
||||
int mTextureHeight = 0;
|
||||
|
@ -128,10 +127,9 @@ private:
|
|||
uint8_t mStencilTestValue = 0;
|
||||
uint8_t mStencilWriteValue = 0;
|
||||
const uint8_t *mColormaps = nullptr;
|
||||
float mClipPlane[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
PolyClipPlane mClipPlane[3];
|
||||
TriBlendMode mBlendMode = TriBlendMode::FillOpaque;
|
||||
uint32_t mLight = 0;
|
||||
uint32_t mSubsectorDepth = 0;
|
||||
uint32_t mColor = 0;
|
||||
uint32_t mSrcAlpha = 0;
|
||||
uint32_t mDestAlpha = 0;
|
||||
|
@ -160,7 +158,7 @@ public:
|
|||
void SetStyle(TriBlendMode blendmode, double srcalpha = 1.0, double destalpha = 1.0) { mBlendMode = blendmode; mSrcAlpha = (uint32_t)(srcalpha * 256.0 + 0.5); mDestAlpha = (uint32_t)(destalpha * 256.0 + 0.5); }
|
||||
void SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FTexture *texture, bool fullbright);
|
||||
void SetColor(uint32_t bgra, uint8_t palindex);
|
||||
void Draw(double x0, double x1, double y0, double y1, double u0, double u1, double v0, double v1);
|
||||
void Draw(PolyRenderThread *thread, double x0, double x1, double y0, double y1, double u0, double u1, double v0, double v1);
|
||||
|
||||
const uint8_t *TexturePixels() const { return mTexturePixels; }
|
||||
int TextureWidth() const { return mTextureWidth; }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Projected triangle drawer
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -42,7 +42,7 @@ namespace TriScreenDrawerModes
|
|||
FORCEINLINE unsigned int Sample32(int32_t u, int32_t v, const uint32_t *texPixels, int texWidth, int texHeight, uint32_t oneU, uint32_t oneV, uint32_t color, const uint32_t *translation)
|
||||
{
|
||||
uint32_t texel;
|
||||
if (SamplerT::Mode == (int)Samplers::Shaded || SamplerT::Mode == (int)Samplers::Stencil || SamplerT::Mode == (int)Samplers::Fill || SamplerT::Mode == (int)Samplers::Fuzz)
|
||||
if (SamplerT::Mode == (int)Samplers::Shaded || SamplerT::Mode == (int)Samplers::Stencil || SamplerT::Mode == (int)Samplers::Fill || SamplerT::Mode == (int)Samplers::Fuzz || SamplerT::Mode == (int)Samplers::FogBoundary)
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
@ -426,6 +426,7 @@ private:
|
|||
bgcolor = 0;
|
||||
|
||||
// Sample fgcolor
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[ix];
|
||||
unsigned int ifgcolor = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
unsigned int ifgshade = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
posU += stepU;
|
||||
|
@ -508,6 +509,7 @@ private:
|
|||
bgcolor = 0;
|
||||
|
||||
// Sample fgcolor
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary && (mask0 & (1 << 31))) color = dest[x];
|
||||
unsigned int ifgcolor = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
unsigned int ifgshade = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
posU += stepU;
|
||||
|
@ -590,6 +592,7 @@ private:
|
|||
bgcolor = 0;
|
||||
|
||||
// Sample fgcolor
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary && (mask1 & (1 << 31))) color = dest[x];
|
||||
unsigned int ifgcolor = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
unsigned int ifgshade = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
posU += stepU;
|
||||
|
@ -765,6 +768,7 @@ private:
|
|||
bgcolor = 0;
|
||||
|
||||
// Sample fgcolor
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = *dest;
|
||||
unsigned int ifgcolor = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
unsigned int ifgshade = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
posU += stepU;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Projected triangle drawer
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -30,7 +30,7 @@ namespace TriScreenDrawerModes
|
|||
FORCEINLINE unsigned int VECTORCALL Sample32(int32_t u, int32_t v, const uint32_t *texPixels, int texWidth, int texHeight, uint32_t oneU, uint32_t oneV, uint32_t color, const uint32_t *translation)
|
||||
{
|
||||
uint32_t texel;
|
||||
if (SamplerT::Mode == (int)Samplers::Shaded || SamplerT::Mode == (int)Samplers::Stencil || SamplerT::Mode == (int)Samplers::Fill || SamplerT::Mode == (int)Samplers::Fuzz)
|
||||
if (SamplerT::Mode == (int)Samplers::Shaded || SamplerT::Mode == (int)Samplers::Stencil || SamplerT::Mode == (int)Samplers::Fill || SamplerT::Mode == (int)Samplers::Fuzz || SamplerT::Mode == (int)Samplers::FogBoundary)
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
@ -430,11 +430,13 @@ private:
|
|||
|
||||
// Sample fgcolor
|
||||
unsigned int ifgcolor[2], ifgshade[2];
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[ix * 2];
|
||||
ifgcolor[0] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[0] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
posU += stepU;
|
||||
posV += stepV;
|
||||
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[ix * 2 + 1];
|
||||
ifgcolor[1] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[1] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
posU += stepU;
|
||||
|
@ -517,11 +519,13 @@ private:
|
|||
|
||||
// Sample fgcolor
|
||||
unsigned int ifgcolor[2], ifgshade[2];
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[x * 2];
|
||||
ifgcolor[0] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[0] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
posU += stepU;
|
||||
posV += stepV;
|
||||
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[x * 2 + 1];
|
||||
ifgcolor[1] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[1] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
posU += stepU;
|
||||
|
@ -606,11 +610,13 @@ private:
|
|||
|
||||
// Sample fgcolor
|
||||
unsigned int ifgcolor[2], ifgshade[2];
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary && (mask1 & (1 << 31))) color = dest[x * 2];
|
||||
ifgcolor[0] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[0] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
posU += stepU;
|
||||
posV += stepV;
|
||||
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary && (mask1 & (1 << 30))) color = dest[x * 2 + 1];
|
||||
ifgcolor[1] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[1] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
posU += stepU;
|
||||
|
@ -780,10 +786,12 @@ private:
|
|||
|
||||
// Sample fgcolor
|
||||
unsigned int ifgcolor[2], ifgshade[2];
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[0];
|
||||
ifgcolor[0] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[0] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
posU += stepU;
|
||||
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = dest[1];
|
||||
ifgcolor[1] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[1] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
posU += stepU;
|
||||
|
@ -809,6 +817,7 @@ private:
|
|||
|
||||
// Sample fgcolor
|
||||
unsigned int ifgcolor[2], ifgshade[2];
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = *dest;
|
||||
ifgcolor[0] = Sample32<SamplerT, FilterModeT>(posU, posV, texPixels, texWidth, texHeight, oneU, oneV, color, translation);
|
||||
ifgshade[0] = SampleShade32<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
ifgcolor[1] = 0;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Projected triangle drawer
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -30,7 +30,7 @@ namespace TriScreenDrawerModes
|
|||
FORCEINLINE unsigned int Sample8(int32_t u, int32_t v, const uint8_t *texPixels, int texWidth, int texHeight, uint32_t color, const uint8_t *translation)
|
||||
{
|
||||
uint8_t texel;
|
||||
if (SamplerT::Mode == (int)Samplers::Shaded || SamplerT::Mode == (int)Samplers::Stencil || SamplerT::Mode == (int)Samplers::Fill || SamplerT::Mode == (int)Samplers::Fuzz)
|
||||
if (SamplerT::Mode == (int)Samplers::Shaded || SamplerT::Mode == (int)Samplers::Stencil || SamplerT::Mode == (int)Samplers::Fill || SamplerT::Mode == (int)Samplers::Fuzz || SamplerT::Mode == (int)Samplers::FogBoundary)
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
@ -290,6 +290,7 @@ public:
|
|||
{
|
||||
int lightshade = lightpos >> 8;
|
||||
uint8_t bgcolor = dest[ix];
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = bgcolor;
|
||||
uint8_t fgcolor = Sample8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, color, translation);
|
||||
uint32_t fgshade = SampleShade8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
if (SamplerT::Mode == (int)Samplers::Fuzz) lightshade = 256;
|
||||
|
@ -339,6 +340,7 @@ public:
|
|||
{
|
||||
int lightshade = lightpos >> 8;
|
||||
uint8_t bgcolor = dest[x];
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = bgcolor;
|
||||
uint8_t fgcolor = Sample8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, color, translation);
|
||||
uint32_t fgshade = SampleShade8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
if (SamplerT::Mode == (int)Samplers::Fuzz) lightshade = 256;
|
||||
|
@ -390,6 +392,7 @@ public:
|
|||
{
|
||||
int lightshade = lightpos >> 8;
|
||||
uint8_t bgcolor = dest[x];
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = bgcolor;
|
||||
uint8_t fgcolor = Sample8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, color, translation);
|
||||
uint32_t fgshade = SampleShade8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
if (SamplerT::Mode == (int)Samplers::Fuzz) lightshade = 256;
|
||||
|
@ -473,6 +476,7 @@ public:
|
|||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
uint8_t bgcolor = *dest;
|
||||
if (SamplerT::Mode == (int)Samplers::FogBoundary) color = bgcolor;
|
||||
uint8_t fgcolor = Sample8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, color, translation);
|
||||
uint32_t fgshade = SampleShade8<SamplerT>(posU, posV, texPixels, texWidth, texHeight, fuzzpos);
|
||||
*dest = ShadeAndBlend8<BlendT>(fgcolor, bgcolor, fgshade, lightshade, colormaps, srcalpha, destalpha);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Triangle drawers
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -99,7 +99,7 @@ void PolyTriangleDrawer::draw_arrays(const PolyDrawArgs &drawargs, WorkerThreadD
|
|||
args.stencilPitch = PolyStencilBuffer::Instance()->BlockWidth();
|
||||
args.stencilValues = PolyStencilBuffer::Instance()->Values();
|
||||
args.stencilMasks = PolyStencilBuffer::Instance()->Masks();
|
||||
args.subsectorGBuffer = PolySubsectorGBuffer::Instance()->Values();
|
||||
args.zbuffer = PolyZBuffer::Instance()->Values();
|
||||
|
||||
bool ccw = drawargs.FaceCullCCW();
|
||||
const TriVertex *vinput = drawargs.Vertices();
|
||||
|
@ -111,28 +111,28 @@ void PolyTriangleDrawer::draw_arrays(const PolyDrawArgs &drawargs, WorkerThreadD
|
|||
for (int i = 0; i < vcount / 3; i++)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
vert[j] = shade_vertex(*drawargs.ObjectToClip(), drawargs.ClipPlane(), *(vinput++));
|
||||
vert[j] = shade_vertex(drawargs, *(vinput++));
|
||||
draw_shaded_triangle(vert, ccw, &args, thread);
|
||||
}
|
||||
}
|
||||
else if (drawargs.DrawMode() == PolyDrawMode::TriangleFan)
|
||||
{
|
||||
vert[0] = shade_vertex(*drawargs.ObjectToClip(), drawargs.ClipPlane(), *(vinput++));
|
||||
vert[1] = shade_vertex(*drawargs.ObjectToClip(), drawargs.ClipPlane(), *(vinput++));
|
||||
vert[0] = shade_vertex(drawargs, *(vinput++));
|
||||
vert[1] = shade_vertex(drawargs, *(vinput++));
|
||||
for (int i = 2; i < vcount; i++)
|
||||
{
|
||||
vert[2] = shade_vertex(*drawargs.ObjectToClip(), drawargs.ClipPlane(), *(vinput++));
|
||||
vert[2] = shade_vertex(drawargs, *(vinput++));
|
||||
draw_shaded_triangle(vert, ccw, &args, thread);
|
||||
vert[1] = vert[2];
|
||||
}
|
||||
}
|
||||
else // TriangleDrawMode::TriangleStrip
|
||||
{
|
||||
vert[0] = shade_vertex(*drawargs.ObjectToClip(), drawargs.ClipPlane(), *(vinput++));
|
||||
vert[1] = shade_vertex(*drawargs.ObjectToClip(), drawargs.ClipPlane(), *(vinput++));
|
||||
vert[0] = shade_vertex(drawargs, *(vinput++));
|
||||
vert[1] = shade_vertex(drawargs, *(vinput++));
|
||||
for (int i = 2; i < vcount; i++)
|
||||
{
|
||||
vert[2] = shade_vertex(*drawargs.ObjectToClip(), drawargs.ClipPlane(), *(vinput++));
|
||||
vert[2] = shade_vertex(drawargs, *(vinput++));
|
||||
draw_shaded_triangle(vert, ccw, &args, thread);
|
||||
vert[0] = vert[1];
|
||||
vert[1] = vert[2];
|
||||
|
@ -141,13 +141,20 @@ void PolyTriangleDrawer::draw_arrays(const PolyDrawArgs &drawargs, WorkerThreadD
|
|||
}
|
||||
}
|
||||
|
||||
ShadedTriVertex PolyTriangleDrawer::shade_vertex(const TriMatrix &objectToClip, const float *clipPlane, const TriVertex &v)
|
||||
ShadedTriVertex PolyTriangleDrawer::shade_vertex(const PolyDrawArgs &drawargs, const TriVertex &v)
|
||||
{
|
||||
// Apply transform to get clip coordinates:
|
||||
ShadedTriVertex sv = objectToClip * v;
|
||||
const TriMatrix &objectToClip = *drawargs.ObjectToClip();
|
||||
|
||||
// Calculate gl_ClipDistance[0]
|
||||
sv.clipDistance0 = v.x * clipPlane[0] + v.y * clipPlane[1] + v.z * clipPlane[2] + v.w * clipPlane[3];
|
||||
// Apply transform to get clip coordinates:
|
||||
ShadedTriVertex sv;
|
||||
sv.position = objectToClip * v;
|
||||
|
||||
// Calculate gl_ClipDistance[i]
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
const auto &clipPlane = drawargs.ClipPlane(i);
|
||||
sv.clipDistance[i] = v.x * clipPlane.A + v.y * clipPlane.B + v.z * clipPlane.C + v.w * clipPlane.D;
|
||||
}
|
||||
|
||||
return sv;
|
||||
}
|
||||
|
@ -155,12 +162,12 @@ ShadedTriVertex PolyTriangleDrawer::shade_vertex(const TriMatrix &objectToClip,
|
|||
bool PolyTriangleDrawer::is_degenerate(const ShadedTriVertex *vert)
|
||||
{
|
||||
// A degenerate triangle has a zero cross product for two of its sides.
|
||||
float ax = vert[1].x - vert[0].x;
|
||||
float ay = vert[1].y - vert[0].y;
|
||||
float az = vert[1].w - vert[0].w;
|
||||
float bx = vert[2].x - vert[0].x;
|
||||
float by = vert[2].y - vert[0].y;
|
||||
float bz = vert[2].w - vert[0].w;
|
||||
float ax = vert[1].position.x - vert[0].position.x;
|
||||
float ay = vert[1].position.y - vert[0].position.y;
|
||||
float az = vert[1].position.w - vert[0].position.w;
|
||||
float bx = vert[2].position.x - vert[0].position.x;
|
||||
float by = vert[2].position.y - vert[0].position.y;
|
||||
float bz = vert[2].position.w - vert[0].position.w;
|
||||
float crossx = ay * bz - az * by;
|
||||
float crossy = az * bx - ax * bz;
|
||||
float crossz = ax * by - ay * bx;
|
||||
|
@ -274,22 +281,25 @@ int PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, TriVertex *clippe
|
|||
// -v.w <= v.z <= v.w
|
||||
|
||||
// halfspace clip distances
|
||||
static const int numclipdistances = 7;
|
||||
static const int numclipdistances = 9;
|
||||
#ifdef NO_SSE
|
||||
float clipdistance[numclipdistances * 3];
|
||||
bool needsclipping = false;
|
||||
float *clipd = clipdistance;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
const auto &v = verts[i];
|
||||
const auto &v = verts[i].position;
|
||||
clipd[0] = v.x + v.w;
|
||||
clipd[1] = v.w - v.x;
|
||||
clipd[2] = v.y + v.w;
|
||||
clipd[3] = v.w - v.y;
|
||||
clipd[4] = v.z + v.w;
|
||||
clipd[5] = v.w - v.z;
|
||||
clipd[6] = v.clipDistance0;
|
||||
needsclipping = needsclipping || clipd[0] < 0.0f || clipd[1] < 0.0f || clipd[2] < 0.0f || clipd[3] < 0.0f || clipd[4] < 0.0f || clipd[5] < 0.0f || clipd[6] < 0.0f;
|
||||
clipd[6] = verts[i].clipDistance[0];
|
||||
clipd[7] = verts[i].clipDistance[1];
|
||||
clipd[8] = verts[i].clipDistance[2];
|
||||
for (int j = 0; j < 9; j++)
|
||||
needsclipping = needsclipping || clipd[i];
|
||||
clipd += numclipdistances;
|
||||
}
|
||||
|
||||
|
@ -298,14 +308,14 @@ int PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, TriVertex *clippe
|
|||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
memcpy(clippedvert + i, verts + i, sizeof(TriVertex));
|
||||
memcpy(clippedvert + i, &verts[i].position, sizeof(TriVertex));
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
#else
|
||||
__m128 mx = _mm_loadu_ps(&verts[0].x);
|
||||
__m128 my = _mm_loadu_ps(&verts[1].x);
|
||||
__m128 mz = _mm_loadu_ps(&verts[2].x);
|
||||
__m128 mx = _mm_loadu_ps(&verts[0].position.x);
|
||||
__m128 my = _mm_loadu_ps(&verts[1].position.x);
|
||||
__m128 mz = _mm_loadu_ps(&verts[2].position.x);
|
||||
__m128 mw = _mm_setzero_ps();
|
||||
_MM_TRANSPOSE4_PS(mx, my, mz, mw);
|
||||
__m128 clipd0 = _mm_add_ps(mx, mw);
|
||||
|
@ -314,7 +324,9 @@ int PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, TriVertex *clippe
|
|||
__m128 clipd3 = _mm_sub_ps(mw, my);
|
||||
__m128 clipd4 = _mm_add_ps(mz, mw);
|
||||
__m128 clipd5 = _mm_sub_ps(mw, mz);
|
||||
__m128 clipd6 = _mm_setr_ps(verts[0].clipDistance0, verts[1].clipDistance0, verts[2].clipDistance0, 0.0f);
|
||||
__m128 clipd6 = _mm_setr_ps(verts[0].clipDistance[0], verts[1].clipDistance[0], verts[2].clipDistance[0], 0.0f);
|
||||
__m128 clipd7 = _mm_setr_ps(verts[0].clipDistance[1], verts[1].clipDistance[1], verts[2].clipDistance[1], 0.0f);
|
||||
__m128 clipd8 = _mm_setr_ps(verts[0].clipDistance[2], verts[1].clipDistance[2], verts[2].clipDistance[2], 0.0f);
|
||||
__m128 mneedsclipping = _mm_cmplt_ps(clipd0, _mm_setzero_ps());
|
||||
mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd1, _mm_setzero_ps()));
|
||||
mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd2, _mm_setzero_ps()));
|
||||
|
@ -322,11 +334,13 @@ int PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, TriVertex *clippe
|
|||
mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd4, _mm_setzero_ps()));
|
||||
mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd5, _mm_setzero_ps()));
|
||||
mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd6, _mm_setzero_ps()));
|
||||
mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd7, _mm_setzero_ps()));
|
||||
mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd8, _mm_setzero_ps()));
|
||||
if (_mm_movemask_ps(mneedsclipping) == 0)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
memcpy(clippedvert + i, verts + i, sizeof(TriVertex));
|
||||
memcpy(clippedvert + i, &verts[i].position, sizeof(TriVertex));
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
@ -338,6 +352,8 @@ int PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, TriVertex *clippe
|
|||
_mm_storeu_ps(clipdistance + 16, clipd4);
|
||||
_mm_storeu_ps(clipdistance + 20, clipd5);
|
||||
_mm_storeu_ps(clipdistance + 24, clipd6);
|
||||
_mm_storeu_ps(clipdistance + 28, clipd7);
|
||||
_mm_storeu_ps(clipdistance + 32, clipd8);
|
||||
#endif
|
||||
|
||||
// use barycentric weights while clipping vertices
|
||||
|
@ -417,12 +433,12 @@ int PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, TriVertex *clippe
|
|||
for (int w = 0; w < 3; w++)
|
||||
{
|
||||
float weight = input[i * 3 + w];
|
||||
v.x += verts[w].x * weight;
|
||||
v.y += verts[w].y * weight;
|
||||
v.z += verts[w].z * weight;
|
||||
v.w += verts[w].w * weight;
|
||||
v.u += verts[w].u * weight;
|
||||
v.v += verts[w].v * weight;
|
||||
v.x += verts[w].position.x * weight;
|
||||
v.y += verts[w].position.y * weight;
|
||||
v.z += verts[w].position.z * weight;
|
||||
v.w += verts[w].position.w * weight;
|
||||
v.u += verts[w].position.u * weight;
|
||||
v.v += verts[w].position.v * weight;
|
||||
}
|
||||
}
|
||||
return inputverts;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Triangle drawers
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -29,9 +29,10 @@
|
|||
#include "polyrenderer/drawers/poly_buffer.h"
|
||||
#include "polyrenderer/drawers/poly_draw_args.h"
|
||||
|
||||
struct ShadedTriVertex : public TriVertex
|
||||
struct ShadedTriVertex
|
||||
{
|
||||
float clipDistance0;
|
||||
TriVertex position;
|
||||
float clipDistance[3];
|
||||
};
|
||||
|
||||
typedef void(*PolyDrawFuncPtr)(const TriDrawTriangleArgs *, WorkerThreadData *);
|
||||
|
@ -44,7 +45,7 @@ public:
|
|||
static bool is_mirror();
|
||||
|
||||
private:
|
||||
static ShadedTriVertex shade_vertex(const TriMatrix &objectToClip, const float *clipPlane, const TriVertex &v);
|
||||
static ShadedTriVertex shade_vertex(const PolyDrawArgs &drawargs, const TriVertex &v);
|
||||
static void draw_arrays(const PolyDrawArgs &args, WorkerThreadData *thread);
|
||||
static void draw_shaded_triangle(const ShadedTriVertex *vertices, bool ccw, TriDrawTriangleArgs *args, WorkerThreadData *thread);
|
||||
static bool is_degenerate(const ShadedTriVertex *vertices);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Triangle drawers
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -47,10 +47,22 @@
|
|||
class TriangleBlock
|
||||
{
|
||||
public:
|
||||
TriangleBlock(const TriDrawTriangleArgs *args);
|
||||
void Loop(const TriDrawTriangleArgs *args, WorkerThreadData *thread);
|
||||
TriangleBlock(const TriDrawTriangleArgs *args, WorkerThreadData *thread);
|
||||
void Render();
|
||||
|
||||
private:
|
||||
void RenderSubdivide(int x0, int y0, int x1, int y1);
|
||||
|
||||
enum class CoverageModes { Full, Partial };
|
||||
struct CoverageFull { static const int Mode = (int)CoverageModes::Full; };
|
||||
struct CoveragePartial { static const int Mode = (int)CoverageModes::Partial; };
|
||||
|
||||
template<typename CoverageMode>
|
||||
void RenderBlock(int x0, int y0, int x1, int y1);
|
||||
|
||||
const TriDrawTriangleArgs *args;
|
||||
WorkerThreadData *thread;
|
||||
|
||||
// Block size, standard 8x8 (must be power of two)
|
||||
static const int q = 8;
|
||||
|
||||
|
@ -76,10 +88,9 @@ private:
|
|||
int clipright;
|
||||
int clipbottom;
|
||||
|
||||
// Subsector buffer
|
||||
uint32_t * RESTRICT subsectorGBuffer;
|
||||
uint32_t subsectorDepth;
|
||||
int32_t subsectorPitch;
|
||||
// Depth buffer
|
||||
float * RESTRICT zbuffer;
|
||||
int32_t zbufferPitch;
|
||||
|
||||
// Triangle bounding block
|
||||
int minx, miny;
|
||||
|
@ -110,16 +121,24 @@ private:
|
|||
__m128i mDY31;
|
||||
#endif
|
||||
|
||||
enum class CoverageResult
|
||||
{
|
||||
full,
|
||||
partial,
|
||||
none
|
||||
};
|
||||
CoverageResult AreaCoverageTest(int x0, int y0, int x1, int y1);
|
||||
|
||||
void CoverageTest();
|
||||
void StencilEqualTest();
|
||||
void StencilGreaterEqualTest();
|
||||
void SubsectorTest();
|
||||
void DepthTest(const TriDrawTriangleArgs *args);
|
||||
void ClipTest();
|
||||
void StencilWrite();
|
||||
void SubsectorWrite();
|
||||
void DepthWrite(const TriDrawTriangleArgs *args);
|
||||
};
|
||||
|
||||
TriangleBlock::TriangleBlock(const TriDrawTriangleArgs *args)
|
||||
TriangleBlock::TriangleBlock(const TriDrawTriangleArgs *args, WorkerThreadData *thread) : args(args), thread(thread)
|
||||
{
|
||||
const TriVertex &v1 = *args->v1;
|
||||
const TriVertex &v2 = *args->v2;
|
||||
|
@ -134,9 +153,8 @@ TriangleBlock::TriangleBlock(const TriDrawTriangleArgs *args)
|
|||
stencilTestValue = args->uniforms->StencilTestValue();
|
||||
stencilWriteValue = args->uniforms->StencilWriteValue();
|
||||
|
||||
subsectorGBuffer = args->subsectorGBuffer;
|
||||
subsectorDepth = args->uniforms->SubsectorDepth();
|
||||
subsectorPitch = args->stencilPitch;
|
||||
zbuffer = args->zbuffer;
|
||||
zbufferPitch = args->stencilPitch;
|
||||
|
||||
// 28.4 fixed-point coordinates
|
||||
#ifdef NO_SSE
|
||||
|
@ -191,9 +209,11 @@ TriangleBlock::TriangleBlock(const TriDrawTriangleArgs *args)
|
|||
return;
|
||||
}
|
||||
|
||||
// Start in corner of 8x8 block
|
||||
// Start and end in corner of 8x8 block
|
||||
minx &= ~(q - 1);
|
||||
miny &= ~(q - 1);
|
||||
maxx |= q - 1;
|
||||
maxy |= q - 1;
|
||||
|
||||
// Half-edge constants
|
||||
C1 = DY12 * X1 - DX12 * Y1;
|
||||
|
@ -227,40 +247,94 @@ TriangleBlock::TriangleBlock(const TriDrawTriangleArgs *args)
|
|||
#endif
|
||||
}
|
||||
|
||||
void TriangleBlock::Loop(const TriDrawTriangleArgs *args, WorkerThreadData *thread)
|
||||
void TriangleBlock::Render()
|
||||
{
|
||||
RenderSubdivide(minx / q, miny / q, (maxx + 1) / q, (maxy + 1) / q);
|
||||
}
|
||||
|
||||
void TriangleBlock::RenderSubdivide(int x0, int y0, int x1, int y1)
|
||||
{
|
||||
CoverageResult result = AreaCoverageTest(x0 * q, y0 * q, x1 * q, y1 * q);
|
||||
if (result == CoverageResult::full)
|
||||
{
|
||||
RenderBlock<CoverageFull>(x0 * q, y0 * q, x1 * q, y1 * q);
|
||||
}
|
||||
else if (result == CoverageResult::partial)
|
||||
{
|
||||
bool doneX = x1 - x0 <= 8;
|
||||
bool doneY = y1 - y0 <= 8;
|
||||
if (doneX && doneY)
|
||||
{
|
||||
RenderBlock<CoveragePartial>(x0 * q, y0 * q, x1 * q, y1 * q);
|
||||
}
|
||||
else
|
||||
{
|
||||
int midx = (x0 + x1) >> 1;
|
||||
int midy = (y0 + y1) >> 1;
|
||||
if (doneX)
|
||||
{
|
||||
RenderSubdivide(x0, y0, x1, midy);
|
||||
RenderSubdivide(x0, midy, x1, y1);
|
||||
}
|
||||
else if (doneY)
|
||||
{
|
||||
RenderSubdivide(x0, y0, midx, y1);
|
||||
RenderSubdivide(midx, y0, x1, y1);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderSubdivide(x0, y0, midx, midy);
|
||||
RenderSubdivide(midx, y0, x1, midy);
|
||||
RenderSubdivide(x0, midy, midx, y1);
|
||||
RenderSubdivide(midx, midy, x1, y1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CoverageModeT>
|
||||
void TriangleBlock::RenderBlock(int x0, int y0, int x1, int y1)
|
||||
{
|
||||
// First block line for this thread
|
||||
int core = thread->core;
|
||||
int num_cores = thread->num_cores;
|
||||
int core_skip = (num_cores - ((miny / q) - core) % num_cores) % num_cores;
|
||||
int start_miny = miny + core_skip * q;
|
||||
int core_skip = (num_cores - ((y0 / q) - core) % num_cores) % num_cores;
|
||||
int start_miny = y0 + core_skip * q;
|
||||
|
||||
bool subsectorTest = args->uniforms->SubsectorTest();
|
||||
bool depthTest = args->uniforms->DepthTest();
|
||||
bool writeColor = args->uniforms->WriteColor();
|
||||
bool writeStencil = args->uniforms->WriteStencil();
|
||||
bool writeSubsector = args->uniforms->WriteSubsector();
|
||||
bool writeDepth = args->uniforms->WriteDepth();
|
||||
|
||||
int bmode = (int)args->uniforms->BlendMode();
|
||||
auto drawFunc = args->destBgra ? ScreenTriangle::TriDrawers32[bmode] : ScreenTriangle::TriDrawers8[bmode];
|
||||
|
||||
// Loop through blocks
|
||||
for (int y = start_miny; y < maxy; y += q * num_cores)
|
||||
for (int y = start_miny; y < y1; y += q * num_cores)
|
||||
{
|
||||
for (int x = minx; x < maxx; x += q)
|
||||
for (int x = x0; x < x1; x += q)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
|
||||
CoverageTest();
|
||||
if (Mask0 == 0 && Mask1 == 0)
|
||||
continue;
|
||||
if (CoverageModeT::Mode == (int)CoverageModes::Full)
|
||||
{
|
||||
Mask0 = 0xffffffff;
|
||||
Mask1 = 0xffffffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
CoverageTest();
|
||||
if (Mask0 == 0 && Mask1 == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
ClipTest();
|
||||
if (Mask0 == 0 && Mask1 == 0)
|
||||
continue;
|
||||
|
||||
// To do: make the stencil test use its own flag for comparison mode instead of abusing the subsector test..
|
||||
if (!subsectorTest)
|
||||
// To do: make the stencil test use its own flag for comparison mode instead of abusing the depth test..
|
||||
if (!depthTest)
|
||||
{
|
||||
StencilEqualTest();
|
||||
if (Mask0 == 0 && Mask1 == 0)
|
||||
|
@ -272,7 +346,7 @@ void TriangleBlock::Loop(const TriDrawTriangleArgs *args, WorkerThreadData *thre
|
|||
if (Mask0 == 0 && Mask1 == 0)
|
||||
continue;
|
||||
|
||||
SubsectorTest();
|
||||
DepthTest(args);
|
||||
if (Mask0 == 0 && Mask1 == 0)
|
||||
continue;
|
||||
}
|
||||
|
@ -281,34 +355,54 @@ void TriangleBlock::Loop(const TriDrawTriangleArgs *args, WorkerThreadData *thre
|
|||
drawFunc(X, Y, Mask0, Mask1, args);
|
||||
if (writeStencil)
|
||||
StencilWrite();
|
||||
if (writeSubsector)
|
||||
SubsectorWrite();
|
||||
if (writeDepth)
|
||||
DepthWrite(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NO_SSE
|
||||
|
||||
void TriangleBlock::SubsectorTest()
|
||||
void TriangleBlock::DepthTest(const TriDrawTriangleArgs *args)
|
||||
{
|
||||
int block = (X >> 3) + (Y >> 3) * subsectorPitch;
|
||||
uint32_t *subsector = subsectorGBuffer + block * 64;
|
||||
int block = (X >> 3) + (Y >> 3) * zbufferPitch;
|
||||
float *depth = zbuffer + block * 64;
|
||||
|
||||
const TriVertex &v1 = *args->v1;
|
||||
|
||||
float stepXW = args->gradientX.W;
|
||||
float stepYW = args->gradientY.W;
|
||||
float posYW = v1.w + stepXW * (X - v1.x) + stepYW * (Y - v1.y);
|
||||
|
||||
uint32_t mask0 = 0;
|
||||
uint32_t mask1 = 0;
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
for (int iy = 0; iy < 4; iy++)
|
||||
{
|
||||
bool covered = *subsector >= subsectorDepth;
|
||||
mask0 <<= 1;
|
||||
mask0 |= (uint32_t)covered;
|
||||
subsector++;
|
||||
float posXW = posYW;
|
||||
for (int ix = 0; ix < 8; ix++)
|
||||
{
|
||||
bool covered = *depth <= posXW;
|
||||
mask0 <<= 1;
|
||||
mask0 |= (uint32_t)covered;
|
||||
depth++;
|
||||
posXW += stepXW;
|
||||
}
|
||||
posYW += stepYW;
|
||||
}
|
||||
for (int i = 0; i < 32; i++)
|
||||
|
||||
for (int iy = 0; iy < 4; iy++)
|
||||
{
|
||||
bool covered = *subsector >= subsectorDepth;
|
||||
mask1 <<= 1;
|
||||
mask1 |= (uint32_t)covered;
|
||||
subsector++;
|
||||
float posXW = posYW;
|
||||
for (int ix = 0; ix < 8; ix++)
|
||||
{
|
||||
bool covered = *depth <= posXW;
|
||||
mask1 <<= 1;
|
||||
mask1 |= (uint32_t)covered;
|
||||
depth++;
|
||||
posXW += stepXW;
|
||||
}
|
||||
posYW += stepYW;
|
||||
}
|
||||
|
||||
Mask0 = Mask0 & mask0;
|
||||
|
@ -317,26 +411,50 @@ void TriangleBlock::SubsectorTest()
|
|||
|
||||
#else
|
||||
|
||||
void TriangleBlock::SubsectorTest()
|
||||
void TriangleBlock::DepthTest(const TriDrawTriangleArgs *args)
|
||||
{
|
||||
int block = (X >> 3) + (Y >> 3) * subsectorPitch;
|
||||
uint32_t *subsector = subsectorGBuffer + block * 64;
|
||||
int block = (X >> 3) + (Y >> 3) * zbufferPitch;
|
||||
float *depth = zbuffer + block * 64;
|
||||
|
||||
const TriVertex &v1 = *args->v1;
|
||||
|
||||
float stepXW = args->gradientX.W;
|
||||
float stepYW = args->gradientY.W;
|
||||
float posYW = v1.w + stepXW * (X - v1.x) + stepYW * (Y - v1.y);
|
||||
|
||||
__m128 mposYW = _mm_setr_ps(posYW, posYW + stepXW, posYW + stepXW + stepXW, posYW + stepXW + stepXW + stepXW);
|
||||
__m128 mstepXW = _mm_set1_ps(stepXW * 4.0f);
|
||||
__m128 mstepYW = _mm_set1_ps(stepYW);
|
||||
|
||||
uint32_t mask0 = 0;
|
||||
uint32_t mask1 = 0;
|
||||
__m128i msubsectorDepth = _mm_set1_epi32(subsectorDepth);
|
||||
__m128i mnotxor = _mm_set1_epi32(0xffffffff);
|
||||
|
||||
for (int iy = 0; iy < 8; iy++)
|
||||
for (int iy = 0; iy < 4; iy++)
|
||||
{
|
||||
mask0 <<= 4;
|
||||
mask0 |= _mm_movemask_ps(_mm_castsi128_ps(_mm_shuffle_epi32(_mm_xor_si128(_mm_cmplt_epi32(_mm_loadu_si128((const __m128i *)subsector), msubsectorDepth), mnotxor), _MM_SHUFFLE(0, 1, 2, 3))));
|
||||
subsector += 4;
|
||||
__m128 mposXW = mposYW;
|
||||
for (int ix = 0; ix < 2; ix++)
|
||||
{
|
||||
__m128 covered = _mm_cmplt_ps(_mm_loadu_ps(depth), mposXW);
|
||||
mask0 <<= 4;
|
||||
mask0 |= _mm_movemask_ps(_mm_shuffle_ps(covered, covered, _MM_SHUFFLE(0, 1, 2, 3)));
|
||||
depth += 4;
|
||||
mposXW = _mm_add_ps(mposXW, mstepXW);
|
||||
}
|
||||
mposYW = _mm_add_ps(mposYW, mstepYW);
|
||||
}
|
||||
for (int iy = 0; iy < 8; iy++)
|
||||
|
||||
for (int iy = 0; iy < 4; iy++)
|
||||
{
|
||||
mask1 <<= 4;
|
||||
mask1 |= _mm_movemask_ps(_mm_castsi128_ps(_mm_shuffle_epi32(_mm_xor_si128(_mm_cmplt_epi32(_mm_loadu_si128((const __m128i *)subsector), msubsectorDepth), mnotxor), _MM_SHUFFLE(0, 1, 2, 3))));
|
||||
subsector += 4;
|
||||
__m128 mposXW = mposYW;
|
||||
for (int ix = 0; ix < 2; ix++)
|
||||
{
|
||||
__m128 covered = _mm_cmplt_ps(_mm_loadu_ps(depth), mposXW);
|
||||
mask1 <<= 4;
|
||||
mask1 |= _mm_movemask_ps(_mm_shuffle_ps(covered, covered, _MM_SHUFFLE(0, 1, 2, 3)));
|
||||
depth += 4;
|
||||
mposXW = _mm_add_ps(mposXW, mstepXW);
|
||||
}
|
||||
mposYW = _mm_add_ps(mposYW, mstepYW);
|
||||
}
|
||||
|
||||
Mask0 = Mask0 & mask0;
|
||||
|
@ -535,6 +653,47 @@ void TriangleBlock::StencilGreaterEqualTest()
|
|||
}
|
||||
}
|
||||
|
||||
TriangleBlock::CoverageResult TriangleBlock::AreaCoverageTest(int x0, int y0, int x1, int y1)
|
||||
{
|
||||
// Corners of block
|
||||
x0 = x0 << 4;
|
||||
x1 = (x1 - 1) << 4;
|
||||
y0 = y0 << 4;
|
||||
y1 = (y1 - 1) << 4;
|
||||
|
||||
// Evaluate half-space functions
|
||||
bool a00 = C1 + DX12 * y0 - DY12 * x0 > 0;
|
||||
bool a10 = C1 + DX12 * y0 - DY12 * x1 > 0;
|
||||
bool a01 = C1 + DX12 * y1 - DY12 * x0 > 0;
|
||||
bool a11 = C1 + DX12 * y1 - DY12 * x1 > 0;
|
||||
int a = (a00 << 0) | (a10 << 1) | (a01 << 2) | (a11 << 3);
|
||||
|
||||
bool b00 = C2 + DX23 * y0 - DY23 * x0 > 0;
|
||||
bool b10 = C2 + DX23 * y0 - DY23 * x1 > 0;
|
||||
bool b01 = C2 + DX23 * y1 - DY23 * x0 > 0;
|
||||
bool b11 = C2 + DX23 * y1 - DY23 * x1 > 0;
|
||||
int b = (b00 << 0) | (b10 << 1) | (b01 << 2) | (b11 << 3);
|
||||
|
||||
bool c00 = C3 + DX31 * y0 - DY31 * x0 > 0;
|
||||
bool c10 = C3 + DX31 * y0 - DY31 * x1 > 0;
|
||||
bool c01 = C3 + DX31 * y1 - DY31 * x0 > 0;
|
||||
bool c11 = C3 + DX31 * y1 - DY31 * x1 > 0;
|
||||
int c = (c00 << 0) | (c10 << 1) | (c01 << 2) | (c11 << 3);
|
||||
|
||||
if (a == 0 || b == 0 || c == 0) // Skip block when outside an edge
|
||||
{
|
||||
return CoverageResult::none;
|
||||
}
|
||||
else if (a == 0xf && b == 0xf && c == 0xf) // Accept whole block when totally covered
|
||||
{
|
||||
return CoverageResult::full;
|
||||
}
|
||||
else // Partially covered block
|
||||
{
|
||||
return CoverageResult::partial;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NO_SSE
|
||||
|
||||
void TriangleBlock::CoverageTest()
|
||||
|
@ -798,65 +957,91 @@ void TriangleBlock::StencilWrite()
|
|||
|
||||
#ifdef NO_SSE
|
||||
|
||||
void TriangleBlock::SubsectorWrite()
|
||||
void TriangleBlock::DepthWrite(const TriDrawTriangleArgs *args)
|
||||
{
|
||||
int block = (X >> 3) + (Y >> 3) * subsectorPitch;
|
||||
uint32_t *subsector = subsectorGBuffer + block * 64;
|
||||
int block = (X >> 3) + (Y >> 3) * zbufferPitch;
|
||||
float *depth = zbuffer + block * 64;
|
||||
|
||||
const TriVertex &v1 = *args->v1;
|
||||
|
||||
float stepXW = args->gradientX.W;
|
||||
float stepYW = args->gradientY.W;
|
||||
float posYW = v1.w + stepXW * (X - v1.x) + stepYW * (Y - v1.y);
|
||||
|
||||
if (Mask0 == 0xffffffff && Mask1 == 0xffffffff)
|
||||
{
|
||||
for (int i = 0; i < 64; i++)
|
||||
for (int iy = 0; iy < 8; iy++)
|
||||
{
|
||||
*(subsector++) = subsectorDepth;
|
||||
float posXW = posYW;
|
||||
for (int ix = 0; ix < 8; ix++)
|
||||
{
|
||||
*(depth++) = posXW;
|
||||
posXW += stepXW;
|
||||
}
|
||||
posYW += stepYW;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t mask0 = Mask0;
|
||||
uint32_t mask1 = Mask1;
|
||||
for (int i = 0; i < 32; i++)
|
||||
|
||||
for (int iy = 0; iy < 4; iy++)
|
||||
{
|
||||
if (mask0 & (1 << 31))
|
||||
*subsector = subsectorDepth;
|
||||
mask0 <<= 1;
|
||||
subsector++;
|
||||
float posXW = posYW;
|
||||
for (int ix = 0; ix < 8; ix++)
|
||||
{
|
||||
if (mask0 & (1 << 31))
|
||||
*depth = posXW;
|
||||
posXW += stepXW;
|
||||
mask0 <<= 1;
|
||||
depth++;
|
||||
}
|
||||
posYW += stepYW;
|
||||
}
|
||||
for (int i = 0; i < 32; i++)
|
||||
|
||||
for (int iy = 0; iy < 4; iy++)
|
||||
{
|
||||
if (mask1 & (1 << 31))
|
||||
*subsector = subsectorDepth;
|
||||
mask1 <<= 1;
|
||||
subsector++;
|
||||
float posXW = posYW;
|
||||
for (int ix = 0; ix < 8; ix++)
|
||||
{
|
||||
if (mask1 & (1 << 31))
|
||||
*depth = posXW;
|
||||
posXW += stepXW;
|
||||
mask1 <<= 1;
|
||||
depth++;
|
||||
}
|
||||
posYW += stepYW;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void TriangleBlock::SubsectorWrite()
|
||||
void TriangleBlock::DepthWrite(const TriDrawTriangleArgs *args)
|
||||
{
|
||||
int block = (X >> 3) + (Y >> 3) * subsectorPitch;
|
||||
uint32_t *subsector = subsectorGBuffer + block * 64;
|
||||
__m128i msubsectorDepth = _mm_set1_epi32(subsectorDepth);
|
||||
int block = (X >> 3) + (Y >> 3) * zbufferPitch;
|
||||
float *depth = zbuffer + block * 64;
|
||||
|
||||
const TriVertex &v1 = *args->v1;
|
||||
|
||||
float stepXW = args->gradientX.W;
|
||||
float stepYW = args->gradientY.W;
|
||||
float posYW = v1.w + stepXW * (X - v1.x) + stepYW * (Y - v1.y);
|
||||
|
||||
__m128 mposYW = _mm_setr_ps(posYW, posYW + stepXW, posYW + stepXW + stepXW, posYW + stepXW + stepXW + stepXW);
|
||||
__m128 mstepXW = _mm_set1_ps(stepXW * 4.0f);
|
||||
__m128 mstepYW = _mm_set1_ps(stepYW);
|
||||
|
||||
if (Mask0 == 0xffffffff && Mask1 == 0xffffffff)
|
||||
{
|
||||
_mm_storeu_si128((__m128i*)subsector, msubsectorDepth); subsector += 4;
|
||||
_mm_storeu_si128((__m128i*)subsector, msubsectorDepth); subsector += 4;
|
||||
_mm_storeu_si128((__m128i*)subsector, msubsectorDepth); subsector += 4;
|
||||
_mm_storeu_si128((__m128i*)subsector, msubsectorDepth); subsector += 4;
|
||||
_mm_storeu_si128((__m128i*)subsector, msubsectorDepth); subsector += 4;
|
||||
_mm_storeu_si128((__m128i*)subsector, msubsectorDepth); subsector += 4;
|
||||
_mm_storeu_si128((__m128i*)subsector, msubsectorDepth); subsector += 4;
|
||||
_mm_storeu_si128((__m128i*)subsector, msubsectorDepth); subsector += 4;
|
||||
_mm_storeu_si128((__m128i*)subsector, msubsectorDepth); subsector += 4;
|
||||
_mm_storeu_si128((__m128i*)subsector, msubsectorDepth); subsector += 4;
|
||||
_mm_storeu_si128((__m128i*)subsector, msubsectorDepth); subsector += 4;
|
||||
_mm_storeu_si128((__m128i*)subsector, msubsectorDepth); subsector += 4;
|
||||
_mm_storeu_si128((__m128i*)subsector, msubsectorDepth); subsector += 4;
|
||||
_mm_storeu_si128((__m128i*)subsector, msubsectorDepth); subsector += 4;
|
||||
_mm_storeu_si128((__m128i*)subsector, msubsectorDepth); subsector += 4;
|
||||
_mm_storeu_si128((__m128i*)subsector, msubsectorDepth);
|
||||
for (int iy = 0; iy < 8; iy++)
|
||||
{
|
||||
__m128 mposXW = mposYW;
|
||||
_mm_storeu_ps(depth, mposXW); depth += 4; mposXW = _mm_add_ps(mposXW, mstepXW);
|
||||
_mm_storeu_ps(depth, mposXW); depth += 4;
|
||||
mposYW = _mm_add_ps(mposYW, mstepYW);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -866,34 +1051,251 @@ void TriangleBlock::SubsectorWrite()
|
|||
__m128i mmask0 = _mm_set1_epi32(Mask0);
|
||||
__m128i mmask1 = _mm_set1_epi32(Mask1);
|
||||
|
||||
_mm_maskmoveu_si128(msubsectorDepth, _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask0, topfour), _mm_setzero_si128()), mxormask), (char*)subsector); mmask0 = _mm_slli_epi32(mmask0, 4); subsector += 4;
|
||||
_mm_maskmoveu_si128(msubsectorDepth, _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask0, topfour), _mm_setzero_si128()), mxormask), (char*)subsector); mmask0 = _mm_slli_epi32(mmask0, 4); subsector += 4;
|
||||
_mm_maskmoveu_si128(msubsectorDepth, _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask0, topfour), _mm_setzero_si128()), mxormask), (char*)subsector); mmask0 = _mm_slli_epi32(mmask0, 4); subsector += 4;
|
||||
_mm_maskmoveu_si128(msubsectorDepth, _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask0, topfour), _mm_setzero_si128()), mxormask), (char*)subsector); mmask0 = _mm_slli_epi32(mmask0, 4); subsector += 4;
|
||||
_mm_maskmoveu_si128(msubsectorDepth, _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask0, topfour), _mm_setzero_si128()), mxormask), (char*)subsector); mmask0 = _mm_slli_epi32(mmask0, 4); subsector += 4;
|
||||
_mm_maskmoveu_si128(msubsectorDepth, _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask0, topfour), _mm_setzero_si128()), mxormask), (char*)subsector); mmask0 = _mm_slli_epi32(mmask0, 4); subsector += 4;
|
||||
_mm_maskmoveu_si128(msubsectorDepth, _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask0, topfour), _mm_setzero_si128()), mxormask), (char*)subsector); mmask0 = _mm_slli_epi32(mmask0, 4); subsector += 4;
|
||||
_mm_maskmoveu_si128(msubsectorDepth, _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask0, topfour), _mm_setzero_si128()), mxormask), (char*)subsector); subsector += 4;
|
||||
for (int iy = 0; iy < 4; iy++)
|
||||
{
|
||||
__m128 mposXW = mposYW;
|
||||
_mm_maskmoveu_si128(_mm_castps_si128(mposXW), _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask0, topfour), _mm_setzero_si128()), mxormask), (char*)depth); mmask0 = _mm_slli_epi32(mmask0, 4); depth += 4; mposXW = _mm_add_ps(mposXW, mstepXW);
|
||||
_mm_maskmoveu_si128(_mm_castps_si128(mposXW), _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask0, topfour), _mm_setzero_si128()), mxormask), (char*)depth); mmask0 = _mm_slli_epi32(mmask0, 4); depth += 4;
|
||||
mposYW = _mm_add_ps(mposYW, mstepYW);
|
||||
}
|
||||
|
||||
_mm_maskmoveu_si128(msubsectorDepth, _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask1, topfour), _mm_setzero_si128()), mxormask), (char*)subsector); mmask1 = _mm_slli_epi32(mmask1, 4); subsector += 4;
|
||||
_mm_maskmoveu_si128(msubsectorDepth, _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask1, topfour), _mm_setzero_si128()), mxormask), (char*)subsector); mmask1 = _mm_slli_epi32(mmask1, 4); subsector += 4;
|
||||
_mm_maskmoveu_si128(msubsectorDepth, _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask1, topfour), _mm_setzero_si128()), mxormask), (char*)subsector); mmask1 = _mm_slli_epi32(mmask1, 4); subsector += 4;
|
||||
_mm_maskmoveu_si128(msubsectorDepth, _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask1, topfour), _mm_setzero_si128()), mxormask), (char*)subsector); mmask1 = _mm_slli_epi32(mmask1, 4); subsector += 4;
|
||||
_mm_maskmoveu_si128(msubsectorDepth, _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask1, topfour), _mm_setzero_si128()), mxormask), (char*)subsector); mmask1 = _mm_slli_epi32(mmask1, 4); subsector += 4;
|
||||
_mm_maskmoveu_si128(msubsectorDepth, _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask1, topfour), _mm_setzero_si128()), mxormask), (char*)subsector); mmask1 = _mm_slli_epi32(mmask1, 4); subsector += 4;
|
||||
_mm_maskmoveu_si128(msubsectorDepth, _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask1, topfour), _mm_setzero_si128()), mxormask), (char*)subsector); mmask1 = _mm_slli_epi32(mmask1, 4); subsector += 4;
|
||||
_mm_maskmoveu_si128(msubsectorDepth, _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask1, topfour), _mm_setzero_si128()), mxormask), (char*)subsector); subsector += 4;
|
||||
for (int iy = 0; iy < 4; iy++)
|
||||
{
|
||||
__m128 mposXW = mposYW;
|
||||
_mm_maskmoveu_si128(_mm_castps_si128(mposXW), _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask1, topfour), _mm_setzero_si128()), mxormask), (char*)depth); mmask1 = _mm_slli_epi32(mmask1, 4); depth += 4; mposXW = _mm_add_ps(mposXW, mstepXW);
|
||||
_mm_maskmoveu_si128(_mm_castps_si128(mposXW), _mm_xor_si128(_mm_cmpeq_epi32(_mm_and_si128(mmask1, topfour), _mm_setzero_si128()), mxormask), (char*)depth); mmask1 = _mm_slli_epi32(mmask1, 4); depth += 4;
|
||||
mposYW = _mm_add_ps(mposYW, mstepYW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
|
||||
void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thread)
|
||||
{
|
||||
TriangleBlock block(args);
|
||||
block.Loop(args, thread);
|
||||
TriangleBlock block(args, thread);
|
||||
block.Render();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void SortVertices(const TriDrawTriangleArgs *args, TriVertex **sortedVertices)
|
||||
{
|
||||
sortedVertices[0] = args->v1;
|
||||
sortedVertices[1] = args->v2;
|
||||
sortedVertices[2] = args->v3;
|
||||
|
||||
if (sortedVertices[1]->y < sortedVertices[0]->y)
|
||||
std::swap(sortedVertices[0], sortedVertices[1]);
|
||||
if (sortedVertices[2]->y < sortedVertices[0]->y)
|
||||
std::swap(sortedVertices[0], sortedVertices[2]);
|
||||
if (sortedVertices[2]->y < sortedVertices[1]->y)
|
||||
std::swap(sortedVertices[1], sortedVertices[2]);
|
||||
}
|
||||
|
||||
void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thread)
|
||||
{
|
||||
// Sort vertices by Y position
|
||||
TriVertex *sortedVertices[3];
|
||||
SortVertices(args, sortedVertices);
|
||||
|
||||
int clipright = args->clipright;
|
||||
int clipbottom = args->clipbottom;
|
||||
|
||||
// Ranges that different triangles edges are active
|
||||
int topY = (int)(sortedVertices[0]->y + 0.5f);
|
||||
int midY = (int)(sortedVertices[1]->y + 0.5f);
|
||||
int bottomY = (int)(sortedVertices[2]->y + 0.5f);
|
||||
|
||||
topY = MAX(topY, 0);
|
||||
midY = clamp(midY, 0, clipbottom);
|
||||
bottomY = MIN(bottomY, clipbottom);
|
||||
|
||||
if (topY >= bottomY)
|
||||
return;
|
||||
|
||||
// Find start/end X positions for each line covered by the triangle:
|
||||
|
||||
int leftEdge[MAXHEIGHT];
|
||||
int rightEdge[MAXHEIGHT];
|
||||
|
||||
float longDX = sortedVertices[2]->x - sortedVertices[0]->x;
|
||||
float longDY = sortedVertices[2]->y - sortedVertices[0]->y;
|
||||
float longStep = longDX / longDY;
|
||||
float longPos = sortedVertices[0]->x + longStep * (topY + 0.5f - sortedVertices[0]->y) + 0.5f;
|
||||
|
||||
if (topY < midY)
|
||||
{
|
||||
float shortDX = sortedVertices[1]->x - sortedVertices[0]->x;
|
||||
float shortDY = sortedVertices[1]->y - sortedVertices[0]->y;
|
||||
float shortStep = shortDX / shortDY;
|
||||
float shortPos = sortedVertices[0]->x + shortStep * (topY + 0.5f - sortedVertices[0]->y) + 0.5f;
|
||||
|
||||
for (int y = topY; y < midY; y++)
|
||||
{
|
||||
int x0 = (int)shortPos;
|
||||
int x1 = (int)longPos;
|
||||
if (x1 < x0) std::swap(x0, x1);
|
||||
x0 = clamp(x0, 0, clipright);
|
||||
x1 = clamp(x1, 0, clipright);
|
||||
|
||||
leftEdge[y] = x0;
|
||||
rightEdge[y] = x1;
|
||||
|
||||
shortPos += shortStep;
|
||||
longPos += longStep;
|
||||
}
|
||||
}
|
||||
|
||||
if (midY < bottomY)
|
||||
{
|
||||
float shortDX = sortedVertices[2]->x - sortedVertices[1]->x;
|
||||
float shortDY = sortedVertices[2]->y - sortedVertices[1]->y;
|
||||
float shortStep = shortDX / shortDY;
|
||||
float shortPos = sortedVertices[1]->x + shortStep * (midY + 0.5f - sortedVertices[1]->y) + 0.5f;
|
||||
|
||||
for (int y = midY; y < bottomY; y++)
|
||||
{
|
||||
int x0 = (int)shortPos;
|
||||
int x1 = (int)longPos;
|
||||
if (x1 < x0) std::swap(x0, x1);
|
||||
x0 = clamp(x0, 0, clipright);
|
||||
x1 = clamp(x1, 0, clipright);
|
||||
|
||||
leftEdge[y] = x0;
|
||||
rightEdge[y] = x1;
|
||||
|
||||
shortPos += shortStep;
|
||||
longPos += longStep;
|
||||
}
|
||||
}
|
||||
|
||||
// Make variables local so the compiler can optimize without worrying about pointer aliasing
|
||||
|
||||
bool depthTest = args->uniforms->DepthTest();
|
||||
bool writeColor = args->uniforms->WriteColor();
|
||||
bool writeStencil = args->uniforms->WriteStencil();
|
||||
bool writeDepth = args->uniforms->WriteDepth();
|
||||
|
||||
uint8_t stencilTestValue = args->uniforms->StencilTestValue();
|
||||
uint8_t stencilWriteValue = args->uniforms->StencilWriteValue();
|
||||
|
||||
int bmode = (int)args->uniforms->BlendMode();
|
||||
auto drawFunc = args->destBgra ? ScreenTriangle::TriDrawers32[bmode] : ScreenTriangle::TriDrawers8[bmode];
|
||||
|
||||
uint8_t *dest = args->dest;
|
||||
uint8_t *stencilbuffer = args->stencilValues;
|
||||
uint32_t *stencilMasks = args->stencilMasks;
|
||||
float *zbuffer = args->zbuffer;
|
||||
int pitch = args->pitch;
|
||||
int stencilpitch = args->stencilPitch * 8;
|
||||
int color = ((int)(ptrdiff_t)args->uniforms->TexturePixels()) >> 2;
|
||||
|
||||
float v1X = args->v1->x;
|
||||
float v1Y = args->v1->y;
|
||||
float v1W = args->v1->w;
|
||||
float v1U = args->v1->u * v1W;
|
||||
float v1V = args->v1->v * v1W;
|
||||
float stepXW = args->gradientX.W;
|
||||
float stepXU = args->gradientX.U;
|
||||
float stepXV = args->gradientX.V;
|
||||
float stepYW = args->gradientY.W;
|
||||
float stepYU = args->gradientY.U;
|
||||
float stepYV = args->gradientY.V;
|
||||
int texWidth = args->uniforms->TextureWidth();
|
||||
int texHeight = args->uniforms->TextureHeight();
|
||||
const uint8_t *texPixels = args->uniforms->TexturePixels();
|
||||
auto colormaps = args->uniforms->BaseColormap();
|
||||
|
||||
bool is_fixed_light = args->uniforms->FixedLight();
|
||||
uint32_t lightmask = is_fixed_light ? 0 : 0xffffffff;
|
||||
uint32_t light = args->uniforms->Light();
|
||||
float shade = 2.0f - (light + 12.0f) / 128.0f;
|
||||
float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f);
|
||||
light += light >> 7; // 255 -> 256
|
||||
|
||||
// Draw the triangle:
|
||||
|
||||
int num_cores = thread->num_cores;
|
||||
for (int y = topY + thread->skipped_by_thread(topY); y < bottomY; y += num_cores)
|
||||
{
|
||||
int x0 = leftEdge[y];
|
||||
int x1 = rightEdge[y];
|
||||
|
||||
uint8_t *destLine = dest + pitch * y;
|
||||
uint8_t *stencilLine = stencilbuffer + stencilpitch * y;
|
||||
float *zbufferLine = zbuffer + stencilpitch * y;
|
||||
|
||||
if ((stencilMasks[y] & 0xffffff00) == 0xffffff00) // First time we draw a line we have to clear the stencil buffer
|
||||
{
|
||||
memset(stencilLine, stencilMasks[y] & 0xff, stencilpitch);
|
||||
stencilMasks[y] = 0;
|
||||
}
|
||||
|
||||
float posXW = v1W + stepXW * (x0 + (0.5f - v1X)) + stepYW * (y + (0.5f - v1Y));
|
||||
float posXU = v1U + stepXU * (x0 + (0.5f - v1X)) + stepYU * (y + (0.5f - v1Y));
|
||||
float posXV = v1V + stepXV * (x0 + (0.5f - v1X)) + stepYV * (y + (0.5f - v1Y));
|
||||
|
||||
int x = x0;
|
||||
while (x < x1)
|
||||
{
|
||||
bool processPixel = true;
|
||||
|
||||
if (!depthTest) // To do: make the stencil test use its own flag for comparison mode instead of abusing the depth test..
|
||||
{
|
||||
processPixel = stencilTestValue == stencilLine[x];
|
||||
}
|
||||
else
|
||||
{
|
||||
processPixel = stencilTestValue >= stencilLine[x] && zbufferLine[x] <= posXW;
|
||||
}
|
||||
|
||||
if (processPixel) // Pixel is visible (passed stencil and depth tests)
|
||||
{
|
||||
if (writeColor)
|
||||
{
|
||||
if (texPixels)
|
||||
{
|
||||
float rcpW = 0x01000000 / posXW;
|
||||
int32_t u = (int32_t)(posXU * rcpW);
|
||||
int32_t v = (int32_t)(posXV * rcpW);
|
||||
|
||||
uint32_t texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16;
|
||||
uint32_t texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16;
|
||||
uint8_t fgcolor = texPixels[texelX * texHeight + texelY];
|
||||
|
||||
fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * posXW), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT);
|
||||
lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask);
|
||||
int lightshade = lightpos >> 8;
|
||||
|
||||
lightshade = ((256 - lightshade) * NUMCOLORMAPS) & 0xffffff00;
|
||||
uint8_t shadedfg = colormaps[lightshade + fgcolor];
|
||||
|
||||
if (fgcolor != 0)
|
||||
destLine[x] = shadedfg;
|
||||
}
|
||||
else
|
||||
{
|
||||
destLine[x] = color;
|
||||
}
|
||||
}
|
||||
if (writeStencil)
|
||||
stencilLine[x] = stencilWriteValue;
|
||||
if (writeDepth)
|
||||
zbufferLine[x] = posXW;
|
||||
}
|
||||
|
||||
posXW += stepXW;
|
||||
posXU += stepXU;
|
||||
posXV += stepXV;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void(*ScreenTriangle::TriDrawers8[])(int, int, uint32_t, uint32_t, const TriDrawTriangleArgs *) =
|
||||
{
|
||||
&TriScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureOpaque
|
||||
|
@ -918,7 +1320,8 @@ void(*ScreenTriangle::TriDrawers8[])(int, int, uint32_t, uint32_t, const TriDraw
|
|||
&TriScreenDrawer8<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillRevSub
|
||||
&TriScreenDrawer8<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillAddSrcColor
|
||||
&TriScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::SkycapSampler>::Execute, // Skycap
|
||||
&TriScreenDrawer8<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::FuzzSampler>::Execute // Fuzz
|
||||
&TriScreenDrawer8<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::FuzzSampler>::Execute, // Fuzz
|
||||
&TriScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::FogBoundarySampler>::Execute, // FogBoundary
|
||||
};
|
||||
|
||||
void(*ScreenTriangle::TriDrawers32[])(int, int, uint32_t, uint32_t, const TriDrawTriangleArgs *) =
|
||||
|
@ -945,7 +1348,8 @@ void(*ScreenTriangle::TriDrawers32[])(int, int, uint32_t, uint32_t, const TriDra
|
|||
&TriScreenDrawer32<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillRevSub
|
||||
&TriScreenDrawer32<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillAddSrcColor
|
||||
&TriScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::SkycapSampler>::Execute, // Skycap
|
||||
&TriScreenDrawer32<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::FuzzSampler>::Execute // Fuzz
|
||||
&TriScreenDrawer32<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::FuzzSampler>::Execute, // Fuzz
|
||||
&TriScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::FogBoundarySampler>::Execute // FogBoundary
|
||||
};
|
||||
|
||||
void(*ScreenTriangle::RectDrawers8[])(const void *, int, int, int, const RectDrawArgs *, WorkerThreadData *) =
|
||||
|
@ -972,7 +1376,8 @@ void(*ScreenTriangle::RectDrawers8[])(const void *, int, int, int, const RectDra
|
|||
&RectScreenDrawer8<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillRevSub
|
||||
&RectScreenDrawer8<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillAddSrcColor
|
||||
&RectScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::SkycapSampler>::Execute, // Skycap
|
||||
&RectScreenDrawer8<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::FuzzSampler>::Execute // Fuzz
|
||||
&RectScreenDrawer8<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::FuzzSampler>::Execute, // Fuzz
|
||||
&RectScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::FogBoundarySampler>::Execute // FogBoundary
|
||||
};
|
||||
|
||||
void(*ScreenTriangle::RectDrawers32[])(const void *, int, int, int, const RectDrawArgs *, WorkerThreadData *) =
|
||||
|
@ -999,7 +1404,8 @@ void(*ScreenTriangle::RectDrawers32[])(const void *, int, int, int, const RectDr
|
|||
&RectScreenDrawer32<TriScreenDrawerModes::RevSubClampBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillRevSub
|
||||
&RectScreenDrawer32<TriScreenDrawerModes::AddSrcColorBlend, TriScreenDrawerModes::FillSampler>::Execute, // FillAddSrcColor
|
||||
&RectScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::SkycapSampler>::Execute, // Skycap
|
||||
&RectScreenDrawer32<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::FuzzSampler>::Execute // Fuzz
|
||||
&RectScreenDrawer32<TriScreenDrawerModes::ShadedBlend, TriScreenDrawerModes::FuzzSampler>::Execute, // Fuzz
|
||||
&RectScreenDrawer32<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::FogBoundarySampler>::Execute, // FogBoundary
|
||||
};
|
||||
|
||||
int ScreenTriangle::FuzzStart = 0;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Projected triangle drawer
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -32,6 +32,13 @@ struct WorkerThreadData
|
|||
{
|
||||
int32_t core;
|
||||
int32_t num_cores;
|
||||
|
||||
// The number of lines to skip to reach the first line to be rendered by this thread
|
||||
int skipped_by_thread(int first_line)
|
||||
{
|
||||
int core_skip = (num_cores - (first_line - core) % num_cores) % num_cores;
|
||||
return core_skip;
|
||||
}
|
||||
};
|
||||
|
||||
struct TriVertex
|
||||
|
@ -60,7 +67,7 @@ struct TriDrawTriangleArgs
|
|||
uint8_t *stencilValues;
|
||||
uint32_t *stencilMasks;
|
||||
int32_t stencilPitch;
|
||||
uint32_t *subsectorGBuffer;
|
||||
float *zbuffer;
|
||||
const PolyDrawArgs *uniforms;
|
||||
bool destBgra;
|
||||
ScreenTriangleStepVariables gradientX;
|
||||
|
@ -120,7 +127,8 @@ enum class TriBlendMode
|
|||
FillRevSub,
|
||||
FillAddSrcColor,
|
||||
Skycap,
|
||||
Fuzz
|
||||
Fuzz,
|
||||
FogBoundary
|
||||
};
|
||||
|
||||
class ScreenTriangle
|
||||
|
@ -157,7 +165,7 @@ namespace TriScreenDrawerModes
|
|||
struct SimpleShade { static const int Mode = (int)ShadeMode::Simple; };
|
||||
struct AdvancedShade { static const int Mode = (int)ShadeMode::Advanced; };
|
||||
|
||||
enum class Samplers { Texture, Fill, Shaded, Stencil, Translated, Skycap, Fuzz };
|
||||
enum class Samplers { Texture, Fill, Shaded, Stencil, Translated, Skycap, Fuzz, FogBoundary };
|
||||
struct TextureSampler { static const int Mode = (int)Samplers::Texture; };
|
||||
struct FillSampler { static const int Mode = (int)Samplers::Fill; };
|
||||
struct ShadedSampler { static const int Mode = (int)Samplers::Shaded; };
|
||||
|
@ -165,6 +173,7 @@ namespace TriScreenDrawerModes
|
|||
struct TranslatedSampler { static const int Mode = (int)Samplers::Translated; };
|
||||
struct SkycapSampler { static const int Mode = (int)Samplers::Skycap; };
|
||||
struct FuzzSampler { static const int Mode = (int)Samplers::Fuzz; };
|
||||
struct FogBoundarySampler { static const int Mode = (int)Samplers::FogBoundary; };
|
||||
|
||||
static const int fuzzcolormap[FUZZTABLE] =
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Triangle drawers
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -173,14 +173,14 @@ TriMatrix TriMatrix::operator*(const TriMatrix &mult) const
|
|||
return result;
|
||||
}
|
||||
|
||||
ShadedTriVertex TriMatrix::operator*(TriVertex v) const
|
||||
TriVertex TriMatrix::operator*(TriVertex v) const
|
||||
{
|
||||
#ifdef NO_SSE
|
||||
float vx = matrix[0 * 4 + 0] * v.x + matrix[1 * 4 + 0] * v.y + matrix[2 * 4 + 0] * v.z + matrix[3 * 4 + 0] * v.w;
|
||||
float vy = matrix[0 * 4 + 1] * v.x + matrix[1 * 4 + 1] * v.y + matrix[2 * 4 + 1] * v.z + matrix[3 * 4 + 1] * v.w;
|
||||
float vz = matrix[0 * 4 + 2] * v.x + matrix[1 * 4 + 2] * v.y + matrix[2 * 4 + 2] * v.z + matrix[3 * 4 + 2] * v.w;
|
||||
float vw = matrix[0 * 4 + 3] * v.x + matrix[1 * 4 + 3] * v.y + matrix[2 * 4 + 3] * v.z + matrix[3 * 4 + 3] * v.w;
|
||||
ShadedTriVertex sv;
|
||||
TriVertex sv;
|
||||
sv.x = vx;
|
||||
sv.y = vy;
|
||||
sv.z = vz;
|
||||
|
@ -196,7 +196,7 @@ ShadedTriVertex TriMatrix::operator*(TriVertex v) const
|
|||
m2 = _mm_mul_ps(m2, _mm_shuffle_ps(mv, mv, _MM_SHUFFLE(2, 2, 2, 2)));
|
||||
m3 = _mm_mul_ps(m3, _mm_shuffle_ps(mv, mv, _MM_SHUFFLE(3, 3, 3, 3)));
|
||||
mv = _mm_add_ps(_mm_add_ps(_mm_add_ps(m0, m1), m2), m3);
|
||||
ShadedTriVertex sv;
|
||||
TriVertex sv;
|
||||
_mm_storeu_ps(&sv.x, mv);
|
||||
#endif
|
||||
sv.u = v.u;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Triangle drawers
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -23,7 +23,6 @@
|
|||
#pragma once
|
||||
|
||||
struct TriVertex;
|
||||
struct ShadedTriVertex;
|
||||
struct FRenderViewpoint;
|
||||
|
||||
struct TriMatrix
|
||||
|
@ -40,7 +39,7 @@ struct TriMatrix
|
|||
//static TriMatrix worldToView(const FRenderViewpoint &viewpoint); // Software renderer world to view space transform
|
||||
//static TriMatrix viewToClip(double focalTangent, double centerY, double invZtoScale); // Software renderer shearing projection
|
||||
|
||||
ShadedTriVertex operator*(TriVertex v) const;
|
||||
TriVertex operator*(TriVertex v) const;
|
||||
TriMatrix operator*(const TriMatrix &m) const;
|
||||
|
||||
float matrix[16];
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "poly_renderer.cpp"
|
||||
#include "poly_renderthread.cpp"
|
||||
#include "drawers/poly_buffer.cpp"
|
||||
#include "drawers/poly_draw_args.cpp"
|
||||
#include "drawers/poly_triangle.cpp"
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "po_man.h"
|
||||
#include "st_stuff.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "p_effect.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "swrenderer/scene/r_scene.h"
|
||||
#include "swrenderer/drawers/r_draw_rgba.h"
|
||||
|
@ -53,7 +54,6 @@ PolyRenderer *PolyRenderer::Instance()
|
|||
|
||||
PolyRenderer::PolyRenderer()
|
||||
{
|
||||
DrawQueue = std::make_shared<DrawerCommandQueue>(&FrameMemory);
|
||||
}
|
||||
|
||||
void PolyRenderer::RenderView(player_t *player)
|
||||
|
@ -74,12 +74,11 @@ void PolyRenderer::RenderView(player_t *player)
|
|||
CameraLight *cameraLight = CameraLight::Instance();
|
||||
if (cameraLight->ShaderColormap() && RenderTarget->IsBgra() && !(r_shadercolormaps && screen->Accel2D))
|
||||
{
|
||||
DrawQueue->Push<ApplySpecialColormapRGBACommand>(cameraLight->ShaderColormap(), screen);
|
||||
Threads.MainThread()->DrawQueue->Push<ApplySpecialColormapRGBACommand>(cameraLight->ShaderColormap(), screen);
|
||||
}
|
||||
|
||||
DrawerThreads::Execute(DrawQueue);
|
||||
Threads.MainThread()->FlushDrawQueue();
|
||||
DrawerThreads::WaitForWorkers();
|
||||
DrawQueue->Clear();
|
||||
}
|
||||
|
||||
void PolyRenderer::RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines)
|
||||
|
@ -97,7 +96,7 @@ void PolyRenderer::RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int
|
|||
canvas->Lock(true);
|
||||
|
||||
RenderActorView(actor, dontmaplines);
|
||||
DrawerThreads::Execute(DrawQueue);
|
||||
Threads.MainThread()->FlushDrawQueue();
|
||||
DrawerThreads::WaitForWorkers();
|
||||
|
||||
canvas->Unlock();
|
||||
|
@ -140,9 +139,9 @@ void PolyRenderer::RenderActorView(AActor *actor, bool dontmaplines)
|
|||
SetupPerspectiveMatrix();
|
||||
MainPortal.SetViewpoint(WorldToClip, PolyClipPlane(0.0f, 0.0f, 0.0f, 1.0f), GetNextStencilValue());
|
||||
MainPortal.Render(0);
|
||||
Skydome.Render(WorldToClip);
|
||||
Skydome.Render(Threads.MainThread(), WorldToClip);
|
||||
MainPortal.RenderTranslucent(0);
|
||||
PlayerSprites.Render();
|
||||
PlayerSprites.Render(Threads.MainThread());
|
||||
|
||||
Viewpoint.camera->renderflags = savedflags;
|
||||
interpolator.RestoreInterpolations ();
|
||||
|
@ -157,9 +156,9 @@ void PolyRenderer::RenderRemainingPlayerSprites()
|
|||
|
||||
void PolyRenderer::ClearBuffers()
|
||||
{
|
||||
FrameMemory.Clear();
|
||||
Threads.Clear();
|
||||
PolyStencilBuffer::Instance()->Clear(RenderTarget->GetWidth(), RenderTarget->GetHeight(), 0);
|
||||
PolySubsectorGBuffer::Instance()->Resize(RenderTarget->GetPitch(), RenderTarget->GetHeight());
|
||||
PolyZBuffer::Instance()->Resize(RenderTarget->GetPitch(), RenderTarget->GetHeight());
|
||||
NextStencilValue = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "scene/poly_sky.h"
|
||||
#include "scene/poly_light.h"
|
||||
#include "swrenderer/r_memory.h"
|
||||
#include "poly_renderthread.h"
|
||||
|
||||
class AActor;
|
||||
class DCanvas;
|
||||
|
@ -54,8 +55,7 @@ public:
|
|||
|
||||
bool DontMapLines = false;
|
||||
|
||||
RenderMemory FrameMemory;
|
||||
DrawerCommandQueuePtr DrawQueue;
|
||||
PolyRenderThreads Threads;
|
||||
DCanvas *RenderTarget = nullptr;
|
||||
FViewWindow Viewwindow;
|
||||
FRenderViewpoint Viewpoint;
|
||||
|
|
264
src/polyrenderer/poly_renderthread.cpp
Normal file
264
src/polyrenderer/poly_renderthread.cpp
Normal file
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "m_bbox.h"
|
||||
#include "i_system.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "p_setup.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "g_level.h"
|
||||
#include "p_effect.h"
|
||||
#include "doomstat.h"
|
||||
#include "r_state.h"
|
||||
#include "v_palette.h"
|
||||
#include "r_sky.h"
|
||||
#include "po_man.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "poly_renderthread.h"
|
||||
#include "poly_renderer.h"
|
||||
#include <mutex>
|
||||
|
||||
#ifdef WIN32
|
||||
void PeekThreadedErrorPane();
|
||||
#endif
|
||||
|
||||
EXTERN_CVAR(Bool, r_scene_multithreaded);
|
||||
|
||||
PolyRenderThread::PolyRenderThread(int threadIndex) : MainThread(threadIndex == 0), ThreadIndex(threadIndex)
|
||||
{
|
||||
FrameMemory.reset(new RenderMemory());
|
||||
DrawQueue = std::make_shared<DrawerCommandQueue>(FrameMemory.get());
|
||||
}
|
||||
|
||||
PolyRenderThread::~PolyRenderThread()
|
||||
{
|
||||
}
|
||||
|
||||
void PolyRenderThread::FlushDrawQueue()
|
||||
{
|
||||
DrawerThreads::Execute(DrawQueue);
|
||||
|
||||
UsedDrawQueues.push_back(DrawQueue);
|
||||
DrawQueue.reset();
|
||||
|
||||
if (!FreeDrawQueues.empty())
|
||||
{
|
||||
DrawQueue = FreeDrawQueues.back();
|
||||
FreeDrawQueues.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawQueue = std::make_shared<DrawerCommandQueue>(FrameMemory.get());
|
||||
}
|
||||
}
|
||||
|
||||
void PolyRenderThread::PrepareTexture(FTexture *texture)
|
||||
{
|
||||
if (texture == nullptr)
|
||||
return;
|
||||
|
||||
// Textures may not have loaded/refreshed yet. The shared code doing
|
||||
// this is not thread safe. By calling GetPixels in a mutex lock we
|
||||
// make sure that only one thread is loading a texture at any given
|
||||
// time.
|
||||
//
|
||||
// It is critical that this function is called before any direct
|
||||
// calls to GetPixels for this to work.
|
||||
|
||||
static std::mutex loadmutex;
|
||||
|
||||
std::unique_lock<std::mutex> lock(loadmutex);
|
||||
|
||||
texture->GetPixels();
|
||||
const FTexture::Span *spans;
|
||||
texture->GetColumn(0, &spans);
|
||||
if (PolyRenderer::Instance()->RenderTarget->IsBgra())
|
||||
{
|
||||
texture->GetPixelsBgra();
|
||||
texture->GetColumnBgra(0, &spans);
|
||||
}
|
||||
}
|
||||
|
||||
void PolyRenderThread::PreparePolyObject(subsector_t *sub)
|
||||
{
|
||||
static std::mutex polyobjmutex;
|
||||
|
||||
std::unique_lock<std::mutex> lock(polyobjmutex);
|
||||
|
||||
if (sub->BSP == nullptr || sub->BSP->bDirty)
|
||||
{
|
||||
sub->BuildPolyBSP();
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyRenderThreads::PolyRenderThreads()
|
||||
{
|
||||
std::unique_ptr<PolyRenderThread> thread(new PolyRenderThread(0));
|
||||
Threads.push_back(std::move(thread));
|
||||
}
|
||||
|
||||
PolyRenderThreads::~PolyRenderThreads()
|
||||
{
|
||||
StopThreads();
|
||||
}
|
||||
|
||||
void PolyRenderThreads::Clear()
|
||||
{
|
||||
for (auto &thread : Threads)
|
||||
{
|
||||
thread->FrameMemory->Clear();
|
||||
thread->DrawQueue->Clear();
|
||||
|
||||
while (!thread->UsedDrawQueues.empty())
|
||||
{
|
||||
auto queue = thread->UsedDrawQueues.back();
|
||||
thread->UsedDrawQueues.pop_back();
|
||||
queue->Clear();
|
||||
thread->FreeDrawQueues.push_back(queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PolyRenderThreads::RenderThreadSlices(int totalcount, std::function<void(PolyRenderThread *)> workerCallback, std::function<void(PolyRenderThread *)> collectCallback)
|
||||
{
|
||||
WorkerCallback = workerCallback;
|
||||
|
||||
int numThreads = std::thread::hardware_concurrency();
|
||||
if (numThreads == 0)
|
||||
numThreads = 4;
|
||||
|
||||
if (!r_scene_multithreaded || !r_multithreaded)
|
||||
numThreads = 1;
|
||||
|
||||
if (numThreads != (int)Threads.size())
|
||||
{
|
||||
StopThreads();
|
||||
StartThreads(numThreads);
|
||||
}
|
||||
|
||||
// Setup threads:
|
||||
std::unique_lock<std::mutex> start_lock(start_mutex);
|
||||
for (int i = 0; i < numThreads; i++)
|
||||
{
|
||||
Threads[i]->Start = totalcount * i / numThreads;
|
||||
Threads[i]->End = totalcount * (i + 1) / numThreads;
|
||||
}
|
||||
run_id++;
|
||||
start_lock.unlock();
|
||||
|
||||
// Notify threads to run
|
||||
if (Threads.size() > 1)
|
||||
{
|
||||
start_condition.notify_all();
|
||||
}
|
||||
|
||||
// Do the main thread ourselves:
|
||||
RenderThreadSlice(MainThread());
|
||||
|
||||
// Wait for everyone to finish:
|
||||
if (Threads.size() > 1)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::unique_lock<std::mutex> end_lock(end_mutex);
|
||||
finished_threads++;
|
||||
if (!end_condition.wait_for(end_lock, 5s, [&]() { return finished_threads == Threads.size(); }))
|
||||
{
|
||||
#ifdef WIN32
|
||||
PeekThreadedErrorPane();
|
||||
#endif
|
||||
// Invoke the crash reporter so that we can capture the call stack of whatever the hung worker thread is doing
|
||||
int *threadCrashed = nullptr;
|
||||
*threadCrashed = 0xdeadbeef;
|
||||
}
|
||||
finished_threads = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numThreads; i++)
|
||||
{
|
||||
Threads[i]->FlushDrawQueue();
|
||||
}
|
||||
|
||||
WorkerCallback = {};
|
||||
|
||||
for (int i = 1; i < numThreads; i++)
|
||||
{
|
||||
collectCallback(Threads[i].get());
|
||||
}
|
||||
}
|
||||
|
||||
void PolyRenderThreads::RenderThreadSlice(PolyRenderThread *thread)
|
||||
{
|
||||
WorkerCallback(thread);
|
||||
}
|
||||
|
||||
void PolyRenderThreads::StartThreads(size_t numThreads)
|
||||
{
|
||||
while (Threads.size() < (size_t)numThreads)
|
||||
{
|
||||
std::unique_ptr<PolyRenderThread> thread(new PolyRenderThread((int)Threads.size()));
|
||||
auto renderthread = thread.get();
|
||||
int start_run_id = run_id;
|
||||
thread->thread = std::thread([=]()
|
||||
{
|
||||
int last_run_id = start_run_id;
|
||||
while (true)
|
||||
{
|
||||
// Wait until we are signalled to run:
|
||||
std::unique_lock<std::mutex> start_lock(start_mutex);
|
||||
start_condition.wait(start_lock, [&]() { return run_id != last_run_id || shutdown_flag; });
|
||||
if (shutdown_flag)
|
||||
break;
|
||||
last_run_id = run_id;
|
||||
start_lock.unlock();
|
||||
|
||||
RenderThreadSlice(renderthread);
|
||||
|
||||
// Notify main thread that we finished:
|
||||
std::unique_lock<std::mutex> end_lock(end_mutex);
|
||||
finished_threads++;
|
||||
end_lock.unlock();
|
||||
end_condition.notify_all();
|
||||
}
|
||||
});
|
||||
Threads.push_back(std::move(thread));
|
||||
}
|
||||
}
|
||||
|
||||
void PolyRenderThreads::StopThreads()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(start_mutex);
|
||||
shutdown_flag = true;
|
||||
lock.unlock();
|
||||
start_condition.notify_all();
|
||||
while (Threads.size() > 1)
|
||||
{
|
||||
Threads.back()->thread.join();
|
||||
Threads.pop_back();
|
||||
}
|
||||
lock.lock();
|
||||
shutdown_flag = false;
|
||||
}
|
91
src/polyrenderer/poly_renderthread.h
Normal file
91
src/polyrenderer/poly_renderthread.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include "swrenderer/r_memory.h"
|
||||
|
||||
class DrawerCommandQueue;
|
||||
typedef std::shared_ptr<DrawerCommandQueue> DrawerCommandQueuePtr;
|
||||
class RenderMemory;
|
||||
|
||||
class PolyRenderThread
|
||||
{
|
||||
public:
|
||||
PolyRenderThread(int threadIndex);
|
||||
~PolyRenderThread();
|
||||
|
||||
void FlushDrawQueue();
|
||||
|
||||
int Start = 0;
|
||||
int End = 0;
|
||||
bool MainThread = false;
|
||||
int ThreadIndex = 0;
|
||||
|
||||
std::unique_ptr<RenderMemory> FrameMemory;
|
||||
DrawerCommandQueuePtr DrawQueue;
|
||||
|
||||
// Make sure texture can accessed safely
|
||||
void PrepareTexture(FTexture *texture);
|
||||
|
||||
// Setup poly object in a threadsafe manner
|
||||
void PreparePolyObject(subsector_t *sub);
|
||||
|
||||
private:
|
||||
std::thread thread;
|
||||
std::vector<DrawerCommandQueuePtr> UsedDrawQueues;
|
||||
std::vector<DrawerCommandQueuePtr> FreeDrawQueues;
|
||||
|
||||
friend class PolyRenderThreads;
|
||||
};
|
||||
|
||||
class PolyRenderThreads
|
||||
{
|
||||
public:
|
||||
PolyRenderThreads();
|
||||
~PolyRenderThreads();
|
||||
|
||||
void Clear();
|
||||
void RenderThreadSlices(int totalcount, std::function<void(PolyRenderThread *)> workerCallback, std::function<void(PolyRenderThread *)> collectCallback);
|
||||
|
||||
PolyRenderThread *MainThread() { return Threads.front().get(); }
|
||||
int NumThreads() const { return (int)Threads.size(); }
|
||||
|
||||
private:
|
||||
void RenderThreadSlice(PolyRenderThread *thread);
|
||||
|
||||
void StartThreads(size_t numThreads);
|
||||
void StopThreads();
|
||||
|
||||
std::function<void(PolyRenderThread *)> WorkerCallback;
|
||||
|
||||
std::vector<std::unique_ptr<PolyRenderThread>> Threads;
|
||||
std::mutex start_mutex;
|
||||
std::condition_variable start_condition;
|
||||
bool shutdown_flag = false;
|
||||
int run_id = 0;
|
||||
std::mutex end_mutex;
|
||||
std::condition_variable end_condition;
|
||||
size_t finished_threads = 0;
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Potential visible set (PVS) handling
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -30,7 +30,35 @@
|
|||
|
||||
void PolyCull::CullScene(const TriMatrix &worldToClip, const PolyClipPlane &portalClipPlane)
|
||||
{
|
||||
ClearSolidSegments();
|
||||
MarkViewFrustum();
|
||||
|
||||
if (level.LevelName != lastLevelName) // Is this the best way to detect a level change?
|
||||
{
|
||||
lastLevelName = level.LevelName;
|
||||
SubsectorDepths.clear();
|
||||
SubsectorDepths.resize(level.subsectors.Size(), 0xffffffff);
|
||||
SectorSeen.clear();
|
||||
SectorSeen.resize(level.sectors.Size());
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto &sub : PvsSectors)
|
||||
SubsectorDepths[sub->Index()] = 0xffffffff;
|
||||
SubsectorDepths.resize(level.subsectors.Size(), 0xffffffff);
|
||||
|
||||
for (const auto §or : SeenSectors)
|
||||
SectorSeen[sector->Index()] = false;
|
||||
SectorSeen.resize(level.sectors.Size());
|
||||
}
|
||||
|
||||
PvsSectors.clear();
|
||||
SeenSectors.clear();
|
||||
|
||||
NextPvsLineStart = 0;
|
||||
PvsLineStart.clear();
|
||||
PvsLineVisible.resize(level.segs.Size());
|
||||
|
||||
PortalClipPlane = portalClipPlane;
|
||||
|
||||
// Cull front to back
|
||||
|
@ -97,35 +125,54 @@ void PolyCull::CullSubsector(subsector_t *sub)
|
|||
FirstSkyHeight = false;
|
||||
}
|
||||
|
||||
uint32_t subsectorDepth = (uint32_t)PvsSectors.size();
|
||||
|
||||
// Mark that we need to render this
|
||||
PvsSectors.push_back(sub);
|
||||
PvsLineStart.push_back(NextPvsLineStart);
|
||||
|
||||
DVector3 viewpos = PolyRenderer::Instance()->Viewpoint.Pos;
|
||||
|
||||
// Update culling info for further bsp clipping
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
if ((line->sidedef == nullptr || !(line->sidedef->Flags & WALLF_POLYOBJ)) && line->backsector == nullptr)
|
||||
|
||||
// Skip lines not facing viewer
|
||||
DVector2 pt1 = line->v1->fPos() - viewpos;
|
||||
DVector2 pt2 = line->v2->fPos() - viewpos;
|
||||
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
|
||||
{
|
||||
// Skip lines not facing viewer
|
||||
DVector2 pt1 = line->v1->fPos() - PolyRenderer::Instance()->Viewpoint.Pos;
|
||||
DVector2 pt2 = line->v2->fPos() - PolyRenderer::Instance()->Viewpoint.Pos;
|
||||
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
|
||||
continue;
|
||||
|
||||
// Skip line if entirely behind portal clipping plane
|
||||
if ((PortalClipPlane.A * line->v1->fX() + PortalClipPlane.B * line->v1->fY() + PortalClipPlane.D <= 0.0) ||
|
||||
(PortalClipPlane.A * line->v2->fX() + PortalClipPlane.B * line->v2->fY() + PortalClipPlane.D <= 0.0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
angle_t angle1, angle2;
|
||||
if (GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2))
|
||||
{
|
||||
MarkSegmentCulled(angle1, angle2);
|
||||
}
|
||||
PvsLineVisible[NextPvsLineStart++] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip line if entirely behind portal clipping plane
|
||||
if ((PortalClipPlane.A * line->v1->fX() + PortalClipPlane.B * line->v1->fY() + PortalClipPlane.D <= 0.0) ||
|
||||
(PortalClipPlane.A * line->v2->fX() + PortalClipPlane.B * line->v2->fY() + PortalClipPlane.D <= 0.0))
|
||||
{
|
||||
PvsLineVisible[NextPvsLineStart++] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
angle_t angle1, angle2;
|
||||
bool lineVisible = GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2);
|
||||
if (lineVisible && line->backsector == nullptr)
|
||||
{
|
||||
MarkSegmentCulled(angle1, angle2);
|
||||
}
|
||||
|
||||
// Mark if this line was visible
|
||||
PvsLineVisible[NextPvsLineStart++] = lineVisible;
|
||||
}
|
||||
|
||||
if (!SectorSeen[sub->sector->Index()])
|
||||
{
|
||||
SectorSeen[sub->sector->Index()] = true;
|
||||
SeenSectors.push_back(sub->sector);
|
||||
}
|
||||
|
||||
SubsectorDepths[sub->Index()] = subsectorDepth;
|
||||
}
|
||||
|
||||
void PolyCull::ClearSolidSegments()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Potential visible set (PVS) handling
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -23,23 +23,27 @@
|
|||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
class PolyCull
|
||||
{
|
||||
public:
|
||||
void ClearSolidSegments();
|
||||
void CullScene(const TriMatrix &worldToClip, const PolyClipPlane &portalClipPlane);
|
||||
|
||||
bool GetAnglesForLine(double x1, double y1, double x2, double y2, angle_t &angle1, angle_t &angle2) const;
|
||||
void MarkSegmentCulled(angle_t angle1, angle_t angle2);
|
||||
bool IsSegmentCulled(angle_t angle1, angle_t angle2) const;
|
||||
void InvertSegments();
|
||||
void MarkViewFrustum();
|
||||
bool IsLineSegVisible(uint32_t subsectorDepth, uint32_t lineIndex)
|
||||
{
|
||||
return PvsLineVisible[PvsLineStart[subsectorDepth] + lineIndex];
|
||||
}
|
||||
|
||||
std::vector<subsector_t *> PvsSectors;
|
||||
double MaxCeilingHeight = 0.0;
|
||||
double MinFloorHeight = 0.0;
|
||||
|
||||
std::vector<sector_t *> SeenSectors;
|
||||
std::vector<bool> SectorSeen;
|
||||
std::vector<uint32_t> SubsectorDepths;
|
||||
|
||||
static angle_t PointToPseudoAngle(double x, double y);
|
||||
|
||||
private:
|
||||
|
@ -49,6 +53,13 @@ private:
|
|||
angle_t Start, End;
|
||||
};
|
||||
|
||||
void ClearSolidSegments();
|
||||
void MarkViewFrustum();
|
||||
|
||||
bool GetAnglesForLine(double x1, double y1, double x2, double y2, angle_t &angle1, angle_t &angle2) const;
|
||||
bool IsSegmentCulled(angle_t angle1, angle_t angle2) const;
|
||||
void InvertSegments();
|
||||
|
||||
void CullNode(void *node);
|
||||
void CullSubsector(subsector_t *sub);
|
||||
int PointOnSide(const DVector2 &pos, const node_t *node);
|
||||
|
@ -57,6 +68,10 @@ private:
|
|||
// Returns true if some part of the bbox might be visible.
|
||||
bool CheckBBox(float *bspcoord);
|
||||
|
||||
void MarkSegmentCulled(angle_t angle1, angle_t angle2);
|
||||
|
||||
FString lastLevelName;
|
||||
|
||||
std::vector<SolidSegment> SolidSegments;
|
||||
std::vector<SolidSegment> TempInvertSolidSegments;
|
||||
const int SolidCullScale = 3000;
|
||||
|
@ -64,5 +79,9 @@ private:
|
|||
|
||||
PolyClipPlane PortalClipPlane;
|
||||
|
||||
std::vector<uint32_t> PvsLineStart;
|
||||
std::vector<bool> PvsLineVisible;
|
||||
uint32_t NextPvsLineStart = 0;
|
||||
|
||||
static angle_t AngleToPseudo(angle_t ang);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Handling drawing a decal
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -28,10 +28,11 @@
|
|||
#include "poly_decal.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "swrenderer/scene/r_scene.h"
|
||||
|
||||
void RenderPolyDecal::RenderWallDecals(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue)
|
||||
void RenderPolyDecal::RenderWallDecals(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const seg_t *line, uint32_t stencilValue)
|
||||
{
|
||||
if (line->linedef == nullptr && line->sidedef == nullptr)
|
||||
return;
|
||||
|
@ -39,11 +40,11 @@ void RenderPolyDecal::RenderWallDecals(const TriMatrix &worldToClip, const PolyC
|
|||
for (DBaseDecal *decal = line->sidedef->AttachedDecals; decal != nullptr; decal = decal->WallNext)
|
||||
{
|
||||
RenderPolyDecal render;
|
||||
render.Render(worldToClip, clipPlane, decal, line, subsectorDepth, stencilValue);
|
||||
render.Render(thread, worldToClip, clipPlane, decal, line, stencilValue);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyDecal::Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, DBaseDecal *decal, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue)
|
||||
void RenderPolyDecal::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, DBaseDecal *decal, const seg_t *line, uint32_t stencilValue)
|
||||
{
|
||||
if (decal->RenderFlags & RF_INVISIBLE || !viewactive || !decal->PicNum.isValid())
|
||||
return;
|
||||
|
@ -52,103 +53,233 @@ void RenderPolyDecal::Render(const TriMatrix &worldToClip, const PolyClipPlane &
|
|||
if (tex == nullptr || tex->UseType == FTexture::TEX_Null)
|
||||
return;
|
||||
|
||||
double edge_right = tex->GetWidth();
|
||||
double edge_left = tex->LeftOffset;
|
||||
edge_right = (edge_right - edge_left) * decal->ScaleX;
|
||||
edge_left *= decal->ScaleX;
|
||||
sector_t *front, *back;
|
||||
GetDecalSectors(decal, line, &front, &back);
|
||||
|
||||
// Calculate unclipped position and UV coordinates
|
||||
|
||||
double edge_left = tex->LeftOffset * decal->ScaleX;
|
||||
double edge_right = (tex->GetWidth() - tex->LeftOffset) * decal->ScaleX;
|
||||
|
||||
DVector2 angvec = (line->v2->fPos() - line->v1->fPos()).Unit();
|
||||
DVector2 normal = { angvec.Y, -angvec.X };
|
||||
|
||||
double dcx, dcy;
|
||||
decal->GetXY(line->sidedef, dcx, dcy);
|
||||
DVector2 decal_pos = { dcx, dcy };
|
||||
|
||||
DVector2 angvec = (line->v2->fPos() - line->v1->fPos()).Unit();
|
||||
DVector2 decal_pos = DVector2(dcx, dcy) + normal;
|
||||
DVector2 decal_left = decal_pos - edge_left * angvec;
|
||||
DVector2 decal_right = decal_pos + edge_right * angvec;
|
||||
|
||||
// Determine actor z
|
||||
double zpos = decal->Z;
|
||||
sector_t *back = (line->backsector != nullptr) ? line->backsector : line->frontsector;
|
||||
bool flipTextureX = (decal->RenderFlags & RF_XFLIP) == RF_XFLIP;
|
||||
double u_left = flipTextureX ? 1.0 : 0.0;
|
||||
double u_right = flipTextureX ? 1.0 - tex->Scale.X : tex->Scale.X;
|
||||
double u_unit = (u_right - u_left) / (edge_left + edge_right);
|
||||
|
||||
// for 3d-floor segments use the model sector as reference
|
||||
sector_t *front;
|
||||
if ((decal->RenderFlags&RF_CLIPMASK) == RF_CLIPMID) front = decal->Sector;
|
||||
else front = line->frontsector;
|
||||
double zpos = GetDecalZ(decal, line, front, back);
|
||||
double spriteHeight = decal->ScaleY / tex->Scale.Y * tex->GetHeight();
|
||||
double ztop = zpos + spriteHeight - spriteHeight * 0.5;
|
||||
double zbottom = zpos - spriteHeight * 0.5;
|
||||
|
||||
switch (decal->RenderFlags & RF_RELMASK)
|
||||
double v_top = 0.0;
|
||||
double v_bottom = tex->Scale.Y;
|
||||
double v_unit = (v_bottom - v_top) / (zbottom - ztop);
|
||||
|
||||
// Clip decal to wall part
|
||||
|
||||
double walltopz, wallbottomz;
|
||||
GetWallZ(decal, line, front, back, walltopz, wallbottomz);
|
||||
|
||||
double clip_left_v1 = (decal_left - line->v1->fPos()) | angvec;
|
||||
double clip_right_v1 = (decal_right - line->v1->fPos()) | angvec;
|
||||
double clip_left_v2 = (decal_left - line->v2->fPos()) | angvec;
|
||||
double clip_right_v2 = (decal_right - line->v2->fPos()) | angvec;
|
||||
|
||||
if ((clip_left_v1 <= 0.0 && clip_right_v1 <= 0.0) || (clip_left_v2 >= 0.0 && clip_right_v2 >= 0.0))
|
||||
return;
|
||||
|
||||
if (clip_left_v1 < 0.0)
|
||||
{
|
||||
default:
|
||||
zpos = decal->Z;
|
||||
break;
|
||||
case RF_RELUPPER:
|
||||
if (line->linedef->flags & ML_DONTPEGTOP)
|
||||
zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
|
||||
else
|
||||
zpos = decal->Z + back->GetPlaneTexZ(sector_t::ceiling);
|
||||
break;
|
||||
case RF_RELLOWER:
|
||||
if (line->linedef->flags & ML_DONTPEGBOTTOM)
|
||||
zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
|
||||
else
|
||||
zpos = decal->Z + back->GetPlaneTexZ(sector_t::floor);
|
||||
break;
|
||||
case RF_RELMID:
|
||||
if (line->linedef->flags & ML_DONTPEGBOTTOM)
|
||||
zpos = decal->Z + front->GetPlaneTexZ(sector_t::floor);
|
||||
else
|
||||
zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
|
||||
decal_left -= angvec * clip_left_v1;
|
||||
u_left -= u_unit * clip_left_v1;
|
||||
}
|
||||
if (clip_right_v1 < 0.0)
|
||||
{
|
||||
decal_right -= angvec * clip_right_v1;
|
||||
u_right -= u_unit * clip_right_v1;
|
||||
}
|
||||
if (clip_left_v2 > 0.0)
|
||||
{
|
||||
decal_left -= angvec * clip_left_v2;
|
||||
u_left -= u_unit * clip_left_v2;
|
||||
}
|
||||
if (clip_right_v2 > 0.0)
|
||||
{
|
||||
decal_right -= angvec * clip_right_v2;
|
||||
u_right -= u_unit * clip_right_v2;
|
||||
}
|
||||
|
||||
DVector2 spriteScale = { decal->ScaleX, decal->ScaleY };
|
||||
double thingxscalemul = spriteScale.X / tex->Scale.X;
|
||||
double thingyscalemul = spriteScale.Y / tex->Scale.Y;
|
||||
double spriteHeight = thingyscalemul * tex->GetHeight();
|
||||
double clip_top_floor = ztop - wallbottomz;
|
||||
double clip_bottom_floor = zbottom - wallbottomz;
|
||||
double clip_top_ceiling = ztop - walltopz;
|
||||
double clip_bottom_ceiling = zbottom - walltopz;
|
||||
|
||||
bool flipTextureX = (decal->RenderFlags & RF_XFLIP) == RF_XFLIP;
|
||||
if ((clip_top_floor <= 0.0 && clip_bottom_floor <= 0.0) || (clip_top_ceiling >= 0.0 && clip_bottom_ceiling >= 0.0))
|
||||
return;
|
||||
|
||||
DVector2 points[2] = { decal_left, decal_right };
|
||||
if (clip_top_floor < 0.0)
|
||||
{
|
||||
ztop -= clip_top_floor;
|
||||
v_top -= v_unit * clip_top_floor;
|
||||
}
|
||||
if (clip_bottom_floor < 0.0)
|
||||
{
|
||||
zbottom -= clip_bottom_floor;
|
||||
v_bottom -= v_unit * clip_bottom_floor;
|
||||
}
|
||||
if (clip_top_ceiling > 0.0)
|
||||
{
|
||||
ztop -= clip_top_ceiling;
|
||||
v_top -= v_unit * clip_top_ceiling;
|
||||
}
|
||||
if (clip_bottom_ceiling > 0.0)
|
||||
{
|
||||
zbottom -= clip_bottom_ceiling;
|
||||
v_bottom -= v_unit * clip_bottom_ceiling;
|
||||
}
|
||||
|
||||
TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(4);
|
||||
// Generate vertices for the decal
|
||||
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
vertices[0].x = (float)decal_left.X;
|
||||
vertices[0].y = (float)decal_left.Y;
|
||||
vertices[0].z = (float)ztop;
|
||||
vertices[0].w = 1.0f;
|
||||
vertices[0].u = (float)u_left;
|
||||
vertices[0].v = (float)v_top;
|
||||
vertices[1].x = (float)decal_right.X;
|
||||
vertices[1].y = (float)decal_right.Y;
|
||||
vertices[1].z = (float)ztop;
|
||||
vertices[1].w = 1.0f;
|
||||
vertices[1].u = (float)u_right;
|
||||
vertices[1].v = (float)v_top;
|
||||
vertices[2].x = (float)decal_right.X;
|
||||
vertices[2].y = (float)decal_right.Y;
|
||||
vertices[2].z = (float)zbottom;
|
||||
vertices[2].w = 1.0f;
|
||||
vertices[2].u = (float)u_right;
|
||||
vertices[2].v = (float)v_bottom;
|
||||
vertices[3].x = (float)decal_left.X;
|
||||
vertices[3].y = (float)decal_left.Y;
|
||||
vertices[3].z = (float)zbottom;
|
||||
vertices[3].w = 1.0f;
|
||||
vertices[3].u = (float)u_left;
|
||||
vertices[3].v = (float)v_bottom;
|
||||
|
||||
// Light calculations
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
|
||||
std::pair<float, float> offsets[4] =
|
||||
{
|
||||
{ 0.0f, 1.0f },
|
||||
{ 1.0f, 1.0f },
|
||||
{ 1.0f, 0.0f },
|
||||
{ 0.0f, 0.0f },
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
auto &p = (i == 0 || i == 3) ? points[0] : points[1];
|
||||
|
||||
vertices[i].x = (float)p.X;
|
||||
vertices[i].y = (float)p.Y;
|
||||
vertices[i].z = (float)(zpos + spriteHeight * offsets[i].second - spriteHeight * 0.5);
|
||||
vertices[i].w = 1.0f;
|
||||
vertices[i].u = (float)(offsets[i].first * tex->Scale.X);
|
||||
vertices[i].v = (float)((1.0f - offsets[i].second) * tex->Scale.Y);
|
||||
if (flipTextureX)
|
||||
vertices[i].u = 1.0f - vertices[i].u;
|
||||
}
|
||||
|
||||
bool fullbrightSprite = (decal->RenderFlags & RF_FULLBRIGHT) == RF_FULLBRIGHT;
|
||||
int lightlevel = fullbrightSprite ? 255 : front->lightlevel + actualextralight;
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(GetColorTable(front->Colormap), lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), fullbrightSprite);
|
||||
args.SetSubsectorDepth(subsectorDepth);
|
||||
args.SetColor(0xff000000 | decal->AlphaColor, decal->AlphaColor >> 24);
|
||||
args.SetStyle(decal->RenderStyle, decal->Alpha, decal->AlphaColor, decal->Translation, tex, false);
|
||||
args.SetTransform(&worldToClip);
|
||||
args.SetFaceCullCCW(true);
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetWriteStencil(true, stencilValue);
|
||||
args.SetClipPlane(clipPlane);
|
||||
args.SetSubsectorDepthTest(true);
|
||||
args.SetClipPlane(0, clipPlane);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteStencil(false);
|
||||
args.SetWriteSubsectorDepth(false);
|
||||
args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
|
||||
args.SetWriteDepth(false);
|
||||
args.DrawArray(thread, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
|
||||
void RenderPolyDecal::GetDecalSectors(DBaseDecal *decal, const seg_t *line, sector_t **front, sector_t **back)
|
||||
{
|
||||
// for 3d-floor segments use the model sector as reference
|
||||
if ((decal->RenderFlags&RF_CLIPMASK) == RF_CLIPMID)
|
||||
*front = decal->Sector;
|
||||
else
|
||||
*front = line->frontsector;
|
||||
|
||||
*back = (line->backsector != nullptr) ? line->backsector : line->frontsector;
|
||||
}
|
||||
|
||||
double RenderPolyDecal::GetDecalZ(DBaseDecal *decal, const seg_t *line, sector_t *front, sector_t *back)
|
||||
{
|
||||
switch (decal->RenderFlags & RF_RELMASK)
|
||||
{
|
||||
default:
|
||||
return decal->Z;
|
||||
case RF_RELUPPER:
|
||||
if (line->linedef->flags & ML_DONTPEGTOP)
|
||||
return decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
|
||||
else
|
||||
return decal->Z + back->GetPlaneTexZ(sector_t::ceiling);
|
||||
case RF_RELLOWER:
|
||||
if (line->linedef->flags & ML_DONTPEGBOTTOM)
|
||||
return decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
|
||||
else
|
||||
return decal->Z + back->GetPlaneTexZ(sector_t::floor);
|
||||
break;
|
||||
case RF_RELMID:
|
||||
if (line->linedef->flags & ML_DONTPEGBOTTOM)
|
||||
return decal->Z + front->GetPlaneTexZ(sector_t::floor);
|
||||
else
|
||||
return decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyDecal::GetWallZ(DBaseDecal *decal, const seg_t *line, sector_t *front, sector_t *back, double &walltopz, double &wallbottomz)
|
||||
{
|
||||
double frontceilz1 = front->ceilingplane.ZatPoint(line->v1);
|
||||
double frontfloorz1 = front->floorplane.ZatPoint(line->v1);
|
||||
double frontceilz2 = front->ceilingplane.ZatPoint(line->v2);
|
||||
double frontfloorz2 = front->floorplane.ZatPoint(line->v2);
|
||||
if (back == nullptr)
|
||||
{
|
||||
walltopz = MAX(frontceilz1, frontceilz2);
|
||||
wallbottomz = MIN(frontfloorz1, frontfloorz2);
|
||||
}
|
||||
else
|
||||
{
|
||||
double backceilz1 = back->ceilingplane.ZatPoint(line->v1);
|
||||
double backfloorz1 = back->floorplane.ZatPoint(line->v1);
|
||||
double backceilz2 = back->ceilingplane.ZatPoint(line->v2);
|
||||
double backfloorz2 = back->floorplane.ZatPoint(line->v2);
|
||||
double topceilz1 = frontceilz1;
|
||||
double topceilz2 = frontceilz2;
|
||||
double topfloorz1 = MAX(MIN(backceilz1, frontceilz1), frontfloorz1);
|
||||
double topfloorz2 = MAX(MIN(backceilz2, frontceilz2), frontfloorz2);
|
||||
double bottomceilz1 = MIN(MAX(frontfloorz1, backfloorz1), frontceilz1);
|
||||
double bottomceilz2 = MIN(MAX(frontfloorz2, backfloorz2), frontceilz2);
|
||||
double bottomfloorz1 = frontfloorz1;
|
||||
double bottomfloorz2 = frontfloorz2;
|
||||
double middleceilz1 = topfloorz1;
|
||||
double middleceilz2 = topfloorz2;
|
||||
double middlefloorz1 = MIN(bottomceilz1, middleceilz1);
|
||||
double middlefloorz2 = MIN(bottomceilz2, middleceilz2);
|
||||
|
||||
switch (decal->RenderFlags & RF_RELMASK)
|
||||
{
|
||||
default:
|
||||
walltopz = MAX(frontceilz1, frontceilz2);
|
||||
wallbottomz = MIN(frontfloorz1, frontfloorz2);
|
||||
break;
|
||||
case RF_RELUPPER:
|
||||
walltopz = MAX(topceilz1, topceilz2);
|
||||
wallbottomz = MIN(topfloorz1, topfloorz2);
|
||||
break;
|
||||
case RF_RELLOWER:
|
||||
walltopz = MAX(bottomceilz1, bottomceilz2);
|
||||
wallbottomz = MIN(bottomfloorz1, bottomfloorz2);
|
||||
break;
|
||||
case RF_RELMID:
|
||||
walltopz = MAX(middleceilz1, middleceilz2);
|
||||
wallbottomz = MIN(middlefloorz1, middlefloorz2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Handling drawing a decal
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -27,8 +27,12 @@
|
|||
class RenderPolyDecal
|
||||
{
|
||||
public:
|
||||
static void RenderWallDecals(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue);
|
||||
static void RenderWallDecals(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, const seg_t *line, uint32_t stencilValue);
|
||||
|
||||
private:
|
||||
void Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, DBaseDecal *decal, const seg_t *line, uint32_t subsectorDepth, uint32_t stencilValue);
|
||||
void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, DBaseDecal *decal, const seg_t *line, uint32_t stencilValue);
|
||||
|
||||
void GetDecalSectors(DBaseDecal *decal, const seg_t *line, sector_t **front, sector_t **back);
|
||||
double GetDecalZ(DBaseDecal *decal, const seg_t *line, sector_t *front, sector_t *back);
|
||||
void GetWallZ(DBaseDecal *decal, const seg_t *line, sector_t *front, sector_t *back, double &walltopz, double &wallbottomz);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Light calculations
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Light calculations
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Particle drawing
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -28,10 +28,11 @@
|
|||
#include "poly_particle.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
|
||||
EXTERN_CVAR(Int, gl_particles_style)
|
||||
|
||||
void RenderPolyParticle::Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue)
|
||||
void RenderPolyParticle::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, particle_t *particle, subsector_t *sub, uint32_t stencilValue)
|
||||
{
|
||||
DVector3 pos = particle->Pos;
|
||||
double psize = particle->size / 8.0;
|
||||
|
@ -45,7 +46,7 @@ void RenderPolyParticle::Render(const TriMatrix &worldToClip, const PolyClipPlan
|
|||
{ pos.X + viewpoint.Sin * psize, pos.Y - viewpoint.Cos * psize }
|
||||
};
|
||||
|
||||
TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(4);
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : viewpoint.extralight << 4;
|
||||
|
@ -75,18 +76,17 @@ void RenderPolyParticle::Render(const TriMatrix &worldToClip, const PolyClipPlan
|
|||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(GetColorTable(sub->sector->Colormap), lightlevel, PolyRenderer::Instance()->Light.ParticleGlobVis(foggy), fullbrightSprite);
|
||||
args.SetSubsectorDepth(subsectorDepth);
|
||||
args.SetSubsectorDepthTest(true);
|
||||
args.SetDepthTest(true);
|
||||
args.SetColor(particle->color | 0xff000000, particle->color >> 24);
|
||||
args.SetStyle(TriBlendMode::Shaded, particle->alpha, 1.0 - particle->alpha);
|
||||
args.SetTransform(&worldToClip);
|
||||
args.SetFaceCullCCW(true);
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetWriteStencil(false);
|
||||
args.SetWriteSubsectorDepth(false);
|
||||
args.SetClipPlane(clipPlane);
|
||||
args.SetWriteDepth(false);
|
||||
args.SetClipPlane(0, clipPlane);
|
||||
args.SetTexture(GetParticleTexture(), ParticleTextureSize, ParticleTextureSize);
|
||||
args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
|
||||
args.DrawArray(thread, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
|
||||
uint8_t *RenderPolyParticle::GetParticleTexture()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Handling drawing a particle
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -28,7 +28,7 @@
|
|||
class RenderPolyParticle
|
||||
{
|
||||
public:
|
||||
void Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue);
|
||||
void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, particle_t *particle, subsector_t *sub, uint32_t stencilValue);
|
||||
|
||||
private:
|
||||
static uint8_t *GetParticleTexture();
|
||||
|
@ -39,3 +39,19 @@ private:
|
|||
ParticleTextureSize = 64
|
||||
};
|
||||
};
|
||||
|
||||
class PolyTranslucentParticle : public PolyTranslucentObject
|
||||
{
|
||||
public:
|
||||
PolyTranslucentParticle(particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue) : PolyTranslucentObject(subsectorDepth, 0.0), particle(particle), sub(sub), StencilValue(stencilValue) { }
|
||||
|
||||
void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &portalPlane) override
|
||||
{
|
||||
RenderPolyParticle spr;
|
||||
spr.Render(thread, worldToClip, portalPlane, particle, sub, StencilValue + 1);
|
||||
}
|
||||
|
||||
particle_t *particle = nullptr;
|
||||
subsector_t *sub = nullptr;
|
||||
uint32_t StencilValue = 0;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Handling drawing a plane (ceiling, floor)
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -30,122 +30,24 @@
|
|||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "r_sky.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
#include "p_lnspec.h"
|
||||
|
||||
EXTERN_CVAR(Int, r_3dfloors)
|
||||
|
||||
void RenderPolyPlane::RenderPlanes(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t ceilingSubsectorDepth, uint32_t floorSubsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals)
|
||||
void RenderPolyPlane::RenderPlanes(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals)
|
||||
{
|
||||
RenderPolyPlane plane;
|
||||
|
||||
if (r_3dfloors)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
auto frontsector = sub->sector;
|
||||
auto &ffloors = frontsector->e->XFloor.ffloors;
|
||||
|
||||
// 3D floor floors
|
||||
for (int i = 0; i < (int)ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *fakeFloor = ffloors[i];
|
||||
if (!(fakeFloor->flags & FF_EXISTS)) continue;
|
||||
if (!fakeFloor->model) continue;
|
||||
if (fakeFloor->bottom.plane->isSlope()) continue;
|
||||
//if (!(fakeFloor->flags & FF_NOSHADE) || (fakeFloor->flags & (FF_RENDERPLANES | FF_RENDERSIDES)))
|
||||
// R_3D_AddHeight(fakeFloor->top.plane, frontsector);
|
||||
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
|
||||
if (fakeFloor->alpha == 0) continue;
|
||||
if (fakeFloor->flags & FF_THISINSIDE && fakeFloor->flags & FF_INVERTSECTOR) continue;
|
||||
//fakeFloor->alpha
|
||||
|
||||
double fakeHeight = fakeFloor->top.plane->ZatPoint(frontsector->centerspot);
|
||||
if (fakeHeight < viewpoint.Pos.Z && fakeHeight > frontsector->floorplane.ZatPoint(frontsector->centerspot))
|
||||
{
|
||||
plane.Render3DFloor(worldToClip, clipPlane, sub, floorSubsectorDepth, stencilValue, false, fakeFloor);
|
||||
}
|
||||
}
|
||||
|
||||
// 3D floor ceilings
|
||||
for (int i = 0; i < (int)ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *fakeFloor = ffloors[i];
|
||||
if (!(fakeFloor->flags & FF_EXISTS)) continue;
|
||||
if (!fakeFloor->model) continue;
|
||||
if (fakeFloor->top.plane->isSlope()) continue;
|
||||
//if (!(fakeFloor->flags & FF_NOSHADE) || (fakeFloor->flags & (FF_RENDERPLANES | FF_RENDERSIDES)))
|
||||
// R_3D_AddHeight(fakeFloor->bottom.plane, frontsector);
|
||||
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
|
||||
if (fakeFloor->alpha == 0) continue;
|
||||
if (!(fakeFloor->flags & FF_THISINSIDE) && (fakeFloor->flags & (FF_SWIMMABLE | FF_INVERTSECTOR)) == (FF_SWIMMABLE | FF_INVERTSECTOR)) continue;
|
||||
//fakeFloor->alpha
|
||||
|
||||
double fakeHeight = fakeFloor->bottom.plane->ZatPoint(frontsector->centerspot);
|
||||
if (fakeHeight > viewpoint.Pos.Z && fakeHeight < frontsector->ceilingplane.ZatPoint(frontsector->centerspot))
|
||||
{
|
||||
plane.Render3DFloor(worldToClip, clipPlane, sub, ceilingSubsectorDepth, stencilValue, true, fakeFloor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plane.Render(worldToClip, clipPlane, cull, sub, ceilingSubsectorDepth, stencilValue, true, skyCeilingHeight, sectorPortals);
|
||||
plane.Render(worldToClip, clipPlane, cull, sub, floorSubsectorDepth, stencilValue, false, skyFloorHeight, sectorPortals);
|
||||
}
|
||||
|
||||
void RenderPolyPlane::Render3DFloor(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, F3DFloor *fakeFloor)
|
||||
{
|
||||
FTextureID picnum = ceiling ? *fakeFloor->bottom.texture : *fakeFloor->top.texture;
|
||||
FTexture *tex = TexMan(picnum);
|
||||
if (tex->UseType == FTexture::TEX_Null)
|
||||
if (sub->sector->CenterFloor() == sub->sector->CenterCeiling())
|
||||
return;
|
||||
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
|
||||
int lightlevel = 255;
|
||||
bool foggy = false;
|
||||
if (cameraLight->FixedLightLevel() < 0 && sub->sector->e->XFloor.lightlist.Size())
|
||||
{
|
||||
lightlist_t *light = P_GetPlaneLight(sub->sector, &sub->sector->ceilingplane, false);
|
||||
//basecolormap = light->extra_colormap;
|
||||
lightlevel = *light->p_lightlevel;
|
||||
}
|
||||
|
||||
UVTransform xform(ceiling ? fakeFloor->top.model->planes[sector_t::ceiling].xform : fakeFloor->top.model->planes[sector_t::floor].xform, tex);
|
||||
|
||||
TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(sub->numlines);
|
||||
if (ceiling)
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[sub->numlines - 1 - i] = PlaneVertex(line->v1, fakeFloor->bottom.plane->ZatPoint(line->v1), xform);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[i] = PlaneVertex(line->v1, fakeFloor->top.plane->ZatPoint(line->v1), xform);
|
||||
}
|
||||
}
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(GetColorTable(sub->sector->Colormap), lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
|
||||
args.SetSubsectorDepth(subsectorDepth);
|
||||
args.SetTransform(&worldToClip);
|
||||
args.SetStyle(TriBlendMode::TextureOpaque);
|
||||
args.SetFaceCullCCW(true);
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetWriteStencil(true, stencilValue + 1);
|
||||
args.SetTexture(tex);
|
||||
args.SetClipPlane(clipPlane);
|
||||
args.DrawArray(vertices, sub->numlines, PolyDrawMode::TriangleFan);
|
||||
RenderPolyPlane plane;
|
||||
plane.Render(thread, worldToClip, clipPlane, sub, stencilValue, true, skyCeilingHeight, sectorPortals);
|
||||
plane.Render(thread, worldToClip, clipPlane, sub, stencilValue, false, skyFloorHeight, sectorPortals);
|
||||
}
|
||||
|
||||
void RenderPolyPlane::Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals)
|
||||
void RenderPolyPlane::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
bool foggy = false;
|
||||
|
||||
sector_t *fakesector = sub->sector->heightsec;
|
||||
if (fakesector && (fakesector == sub->sector || (fakesector->MoreFlags & SECF_IGNOREHEIGHTSEC) == SECF_IGNOREHEIGHTSEC))
|
||||
|
@ -279,48 +181,88 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const PolyClipPlane &
|
|||
#endif
|
||||
}
|
||||
|
||||
UVTransform transform(ceiling ? frontsector->planes[sector_t::ceiling].xform : frontsector->planes[sector_t::floor].xform, tex);
|
||||
PolyPlaneUVTransform transform(ceiling ? frontsector->planes[sector_t::ceiling].xform : frontsector->planes[sector_t::floor].xform, tex);
|
||||
|
||||
TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(sub->numlines);
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(sub->numlines);
|
||||
|
||||
if (ceiling)
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
if (!isSky)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[sub->numlines - 1 - i] = PlaneVertex(line->v1, isSky ? skyHeight : frontsector->ceilingplane.ZatPoint(line->v1), transform);
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[sub->numlines - 1 - i] = transform.GetVertex(line->v1, frontsector->ceilingplane.ZatPoint(line->v1));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[sub->numlines - 1 - i] = transform.GetVertex(line->v1, skyHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
if (!isSky)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[i] = PlaneVertex(line->v1, isSky ? skyHeight : frontsector->floorplane.ZatPoint(line->v1), transform);
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[i] = transform.GetVertex(line->v1, frontsector->floorplane.ZatPoint(line->v1));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[i] = transform.GetVertex(line->v1, skyHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool foggy = level.fadeto || frontsector->Colormap.FadeColor || (level.flags & LEVEL_HASFADETABLE);
|
||||
|
||||
int lightlevel = ceiling ? frontsector->GetCeilingLight() : frontsector->GetFloorLight();
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
lightlevel = clamp(lightlevel + actualextralight, 0, 255);
|
||||
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
FDynamicColormap *basecolormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[ceiling ? sector_t::ceiling : sector_t::floor]);
|
||||
if (cameraLight->FixedLightLevel() < 0 && frontsector->e && frontsector->e->XFloor.lightlist.Size())
|
||||
{
|
||||
lightlist_t *light = P_GetPlaneLight(frontsector, ceiling ? &frontsector->ceilingplane : &frontsector->floorplane, false);
|
||||
basecolormap = GetColorTable(light->extra_colormap, frontsector->SpecialColors[ceiling ? sector_t::ceiling : sector_t::floor]);
|
||||
if (light->p_lightlevel != &frontsector->lightlevel) // If this is the real ceiling, don't discard plane lighting R_FakeFlat() accounted for.
|
||||
{
|
||||
lightlevel = *light->p_lightlevel;
|
||||
}
|
||||
}
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(GetColorTable(frontsector->Colormap, frontsector->SpecialColors[ceiling]), frontsector->lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
|
||||
args.SetSubsectorDepth(isSky ? RenderPolyScene::SkySubsectorDepth : subsectorDepth);
|
||||
args.SetLight(basecolormap, lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
|
||||
//args.SetSubsectorDepth(isSky ? RenderPolyScene::SkySubsectorDepth : subsectorDepth);
|
||||
args.SetTransform(&worldToClip);
|
||||
args.SetFaceCullCCW(ccw);
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetWriteStencil(true, stencilValue + 1);
|
||||
args.SetClipPlane(clipPlane);
|
||||
args.SetClipPlane(0, clipPlane);
|
||||
|
||||
if (!isSky)
|
||||
{
|
||||
args.SetTexture(tex);
|
||||
args.SetStyle(TriBlendMode::TextureOpaque);
|
||||
args.DrawArray(vertices, sub->numlines, PolyDrawMode::TriangleFan);
|
||||
args.DrawArray(thread, vertices, sub->numlines, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (portal)
|
||||
{
|
||||
args.SetWriteStencil(true, polyportal->StencilValue);
|
||||
polyportal->Shape.push_back({ vertices, (int)sub->numlines, ccw, subsectorDepth });
|
||||
polyportal->Shape.push_back({ vertices, (int)sub->numlines, ccw });
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -328,31 +270,40 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const PolyClipPlane &
|
|||
}
|
||||
|
||||
args.SetWriteColor(false);
|
||||
args.SetWriteSubsectorDepth(false);
|
||||
args.DrawArray(vertices, sub->numlines, PolyDrawMode::TriangleFan);
|
||||
args.SetWriteDepth(false);
|
||||
args.DrawArray(thread, vertices, sub->numlines, PolyDrawMode::TriangleFan);
|
||||
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
RenderSkyWalls(thread, args, sub, frontsector, portal, polyportal, ceiling, skyHeight, transform);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyPlane::RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, sector_t *frontsector, FSectorPortal *portal, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight, const PolyPlaneUVTransform &transform)
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
|
||||
double skyBottomz1 = frontsector->ceilingplane.ZatPoint(line->v1);
|
||||
double skyBottomz2 = frontsector->ceilingplane.ZatPoint(line->v2);
|
||||
if (line->backsector)
|
||||
{
|
||||
TriVertex *wallvert = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(4);
|
||||
sector_t *backsector = line->backsector;
|
||||
|
||||
seg_t *line = &sub->firstline[i];
|
||||
double backceilz1 = backsector->ceilingplane.ZatPoint(line->v1);
|
||||
double backfloorz1 = backsector->floorplane.ZatPoint(line->v1);
|
||||
double backceilz2 = backsector->ceilingplane.ZatPoint(line->v2);
|
||||
double backfloorz2 = backsector->floorplane.ZatPoint(line->v2);
|
||||
|
||||
double skyBottomz1 = frontsector->ceilingplane.ZatPoint(line->v1);
|
||||
double skyBottomz2 = frontsector->ceilingplane.ZatPoint(line->v2);
|
||||
if (line->backsector)
|
||||
bool bothSkyCeiling = frontsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum;
|
||||
|
||||
bool closedSector = backceilz1 == backfloorz1 && backceilz2 == backfloorz2;
|
||||
if (ceiling && bothSkyCeiling && closedSector)
|
||||
{
|
||||
sector_t *backsector = (line->backsector != line->frontsector) ? line->backsector : line->frontsector;
|
||||
|
||||
double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1);
|
||||
double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1);
|
||||
double frontceilz2 = frontsector->ceilingplane.ZatPoint(line->v2);
|
||||
double frontfloorz2 = frontsector->floorplane.ZatPoint(line->v2);
|
||||
|
||||
double backceilz1 = backsector->ceilingplane.ZatPoint(line->v1);
|
||||
double backfloorz1 = backsector->floorplane.ZatPoint(line->v1);
|
||||
double backceilz2 = backsector->ceilingplane.ZatPoint(line->v2);
|
||||
double backfloorz2 = backsector->floorplane.ZatPoint(line->v2);
|
||||
|
||||
double topceilz1 = frontceilz1;
|
||||
double topceilz2 = frontceilz2;
|
||||
double topfloorz1 = MIN(backceilz1, frontceilz1);
|
||||
|
@ -364,58 +315,50 @@ void RenderPolyPlane::Render(const TriMatrix &worldToClip, const PolyClipPlane &
|
|||
double middlefloorz1 = MIN(bottomceilz1, middleceilz1);
|
||||
double middlefloorz2 = MIN(bottomceilz2, middleceilz2);
|
||||
|
||||
bool bothSkyCeiling = frontsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum;
|
||||
|
||||
bool closedSector = backceilz1 == backfloorz1 && backceilz2 == backfloorz2;
|
||||
if (ceiling && bothSkyCeiling && closedSector)
|
||||
{
|
||||
skyBottomz1 = middlefloorz1;
|
||||
skyBottomz2 = middlefloorz2;
|
||||
}
|
||||
else if (bothSkyCeiling)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
skyBottomz1 = middlefloorz1;
|
||||
skyBottomz2 = middlefloorz2;
|
||||
}
|
||||
|
||||
if (ceiling)
|
||||
else if (bothSkyCeiling)
|
||||
{
|
||||
wallvert[0] = PlaneVertex(line->v1, skyHeight, transform);
|
||||
wallvert[1] = PlaneVertex(line->v2, skyHeight, transform);
|
||||
wallvert[2] = PlaneVertex(line->v2, skyBottomz2, transform);
|
||||
wallvert[3] = PlaneVertex(line->v1, skyBottomz1, transform);
|
||||
}
|
||||
else
|
||||
{
|
||||
wallvert[0] = PlaneVertex(line->v1, frontsector->floorplane.ZatPoint(line->v1), transform);
|
||||
wallvert[1] = PlaneVertex(line->v2, frontsector->floorplane.ZatPoint(line->v2), transform);
|
||||
wallvert[2] = PlaneVertex(line->v2, skyHeight, transform);
|
||||
wallvert[3] = PlaneVertex(line->v1, skyHeight, transform);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (portal && line->linedef && line->linedef->special == Line_Horizon)
|
||||
{
|
||||
// Not entirely correct as this closes the line horizon rather than allowing the floor to continue to infinity
|
||||
skyBottomz1 = frontsector->floorplane.ZatPoint(line->v1);
|
||||
skyBottomz2 = frontsector->floorplane.ZatPoint(line->v2);
|
||||
}
|
||||
|
||||
args.DrawArray(wallvert, 4, PolyDrawMode::TriangleFan);
|
||||
|
||||
if (portal)
|
||||
{
|
||||
polyportal->Shape.push_back({ wallvert, 4, ccw, subsectorDepth });
|
||||
}
|
||||
TriVertex *wallvert = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
|
||||
if (ceiling)
|
||||
{
|
||||
wallvert[0] = transform.GetVertex(line->v1, skyHeight);
|
||||
wallvert[1] = transform.GetVertex(line->v2, skyHeight);
|
||||
wallvert[2] = transform.GetVertex(line->v2, skyBottomz2);
|
||||
wallvert[3] = transform.GetVertex(line->v1, skyBottomz1);
|
||||
}
|
||||
else
|
||||
{
|
||||
wallvert[0] = transform.GetVertex(line->v1, frontsector->floorplane.ZatPoint(line->v1));
|
||||
wallvert[1] = transform.GetVertex(line->v2, frontsector->floorplane.ZatPoint(line->v2));
|
||||
wallvert[2] = transform.GetVertex(line->v2, skyHeight);
|
||||
wallvert[3] = transform.GetVertex(line->v1, skyHeight);
|
||||
}
|
||||
|
||||
args.DrawArray(thread, wallvert, 4, PolyDrawMode::TriangleFan);
|
||||
|
||||
if (portal)
|
||||
{
|
||||
polyportal->Shape.push_back({ wallvert, 4, args.FaceCullCCW() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TriVertex RenderPolyPlane::PlaneVertex(vertex_t *v1, double height, const UVTransform &transform)
|
||||
{
|
||||
TriVertex v;
|
||||
v.x = (float)v1->fPos().X;
|
||||
v.y = (float)v1->fPos().Y;
|
||||
v.z = (float)height;
|
||||
v.w = 1.0f;
|
||||
v.u = transform.GetU(v.x, v.y);
|
||||
v.v = transform.GetV(v.x, v.y);
|
||||
return v;
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RenderPolyPlane::UVTransform::UVTransform(const FTransform &transform, FTexture *tex)
|
||||
PolyPlaneUVTransform::PolyPlaneUVTransform(const FTransform &transform, FTexture *tex)
|
||||
{
|
||||
if (tex)
|
||||
{
|
||||
|
@ -440,12 +383,160 @@ RenderPolyPlane::UVTransform::UVTransform(const FTransform &transform, FTexture
|
|||
}
|
||||
}
|
||||
|
||||
float RenderPolyPlane::UVTransform::GetU(float x, float y) const
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Render3DFloorPlane::RenderPlanes(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, uint32_t subsectorDepth, std::vector<PolyTranslucentObject *> &translucentObjects)
|
||||
{
|
||||
return (xOffs + x * cosine - y * sine) * xscale;
|
||||
if (!r_3dfloors || sub->sector->CenterFloor() == sub->sector->CenterCeiling())
|
||||
return;
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
auto frontsector = sub->sector;
|
||||
auto &ffloors = frontsector->e->XFloor.ffloors;
|
||||
|
||||
// 3D floor floors
|
||||
for (int i = 0; i < (int)ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *fakeFloor = ffloors[i];
|
||||
if (!(fakeFloor->flags & FF_EXISTS)) continue;
|
||||
if (!fakeFloor->model) continue;
|
||||
//if (!(fakeFloor->flags & FF_NOSHADE) || (fakeFloor->flags & (FF_RENDERPLANES | FF_RENDERSIDES)))
|
||||
// R_3D_AddHeight(fakeFloor->top.plane, frontsector);
|
||||
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
|
||||
if (fakeFloor->alpha == 0) continue;
|
||||
if (fakeFloor->flags & FF_THISINSIDE && fakeFloor->flags & FF_INVERTSECTOR) continue;
|
||||
//fakeFloor->alpha
|
||||
|
||||
double fakeHeight = fakeFloor->top.plane->ZatPoint(frontsector->centerspot);
|
||||
if (fakeFloor->bottom.plane->isSlope() || (fakeHeight < viewpoint.Pos.Z && fakeHeight > frontsector->floorplane.ZatPoint(frontsector->centerspot)))
|
||||
{
|
||||
Render3DFloorPlane plane;
|
||||
plane.sub = sub;
|
||||
plane.stencilValue = stencilValue;
|
||||
plane.ceiling = false;
|
||||
plane.fakeFloor = fakeFloor;
|
||||
plane.Additive = !!(fakeFloor->flags & FF_ADDITIVETRANS);
|
||||
if (!plane.Additive && fakeFloor->alpha == 255)
|
||||
{
|
||||
plane.Masked = false;
|
||||
plane.Alpha = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
plane.Masked = true;
|
||||
plane.Alpha = fakeFloor->alpha / 255.0;
|
||||
}
|
||||
|
||||
if (!plane.Masked)
|
||||
plane.Render(thread, worldToClip, clipPlane);
|
||||
else
|
||||
translucentObjects.push_back(thread->FrameMemory->NewObject<PolyTranslucent3DFloorPlane>(plane, subsectorDepth));
|
||||
}
|
||||
}
|
||||
|
||||
// 3D floor ceilings
|
||||
for (int i = 0; i < (int)ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *fakeFloor = ffloors[i];
|
||||
if (!(fakeFloor->flags & FF_EXISTS)) continue;
|
||||
if (!fakeFloor->model) continue;
|
||||
//if (!(fakeFloor->flags & FF_NOSHADE) || (fakeFloor->flags & (FF_RENDERPLANES | FF_RENDERSIDES)))
|
||||
// R_3D_AddHeight(fakeFloor->bottom.plane, frontsector);
|
||||
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
|
||||
if (fakeFloor->alpha == 0) continue;
|
||||
if (!(fakeFloor->flags & FF_THISINSIDE) && (fakeFloor->flags & (FF_SWIMMABLE | FF_INVERTSECTOR)) == (FF_SWIMMABLE | FF_INVERTSECTOR)) continue;
|
||||
//fakeFloor->alpha
|
||||
|
||||
double fakeHeight = fakeFloor->bottom.plane->ZatPoint(frontsector->centerspot);
|
||||
if (fakeFloor->bottom.plane->isSlope() || (fakeHeight > viewpoint.Pos.Z && fakeHeight < frontsector->ceilingplane.ZatPoint(frontsector->centerspot)))
|
||||
{
|
||||
Render3DFloorPlane plane;
|
||||
plane.sub = sub;
|
||||
plane.stencilValue = stencilValue;
|
||||
plane.ceiling = true;
|
||||
plane.fakeFloor = fakeFloor;
|
||||
plane.Additive = !!(fakeFloor->flags & FF_ADDITIVETRANS);
|
||||
if (!plane.Additive && fakeFloor->alpha == 255)
|
||||
{
|
||||
plane.Masked = false;
|
||||
plane.Alpha = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
plane.Masked = true;
|
||||
plane.Alpha = fakeFloor->alpha / 255.0;
|
||||
}
|
||||
|
||||
if (!plane.Masked)
|
||||
plane.Render(thread, worldToClip, clipPlane);
|
||||
else
|
||||
translucentObjects.push_back(thread->FrameMemory->NewObject<PolyTranslucent3DFloorPlane>(plane, subsectorDepth));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float RenderPolyPlane::UVTransform::GetV(float x, float y) const
|
||||
void Render3DFloorPlane::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane)
|
||||
{
|
||||
return (yOffs - x * sine - y * cosine) * yscale;
|
||||
FTextureID picnum = ceiling ? *fakeFloor->bottom.texture : *fakeFloor->top.texture;
|
||||
FTexture *tex = TexMan(picnum);
|
||||
if (tex->UseType == FTexture::TEX_Null)
|
||||
return;
|
||||
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
|
||||
int lightlevel = 255;
|
||||
bool foggy = false;
|
||||
if (cameraLight->FixedLightLevel() < 0 && sub->sector->e->XFloor.lightlist.Size())
|
||||
{
|
||||
lightlist_t *light = P_GetPlaneLight(sub->sector, &sub->sector->ceilingplane, false);
|
||||
//basecolormap = light->extra_colormap;
|
||||
lightlevel = *light->p_lightlevel;
|
||||
}
|
||||
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
lightlevel = clamp(lightlevel + actualextralight, 0, 255);
|
||||
|
||||
PolyPlaneUVTransform xform(ceiling ? fakeFloor->top.model->planes[sector_t::ceiling].xform : fakeFloor->top.model->planes[sector_t::floor].xform, tex);
|
||||
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(sub->numlines);
|
||||
if (ceiling)
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[sub->numlines - 1 - i] = xform.GetVertex(line->v1, fakeFloor->bottom.plane->ZatPoint(line->v1));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[i] = xform.GetVertex(line->v1, fakeFloor->top.plane->ZatPoint(line->v1));
|
||||
}
|
||||
}
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(GetColorTable(sub->sector->Colormap), lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
|
||||
args.SetTransform(&worldToClip);
|
||||
if (!Masked)
|
||||
{
|
||||
args.SetStyle(TriBlendMode::TextureOpaque);
|
||||
}
|
||||
else
|
||||
{
|
||||
double srcalpha = MIN(Alpha, 1.0);
|
||||
double destalpha = Additive ? 1.0 : 1.0 - srcalpha;
|
||||
args.SetStyle(TriBlendMode::TextureAdd, srcalpha, destalpha);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
args.SetWriteStencil(false);
|
||||
}
|
||||
args.SetFaceCullCCW(true);
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetWriteStencil(true, stencilValue + 1);
|
||||
args.SetTexture(tex);
|
||||
args.SetClipPlane(0, clipPlane);
|
||||
args.DrawArray(thread, vertices, sub->numlines, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Handling drawing a plane (ceiling, floor)
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -25,29 +25,70 @@
|
|||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
class PolyDrawSectorPortal;
|
||||
class PolyCull;
|
||||
|
||||
class PolyPlaneUVTransform
|
||||
{
|
||||
public:
|
||||
PolyPlaneUVTransform(const FTransform &transform, FTexture *tex);
|
||||
|
||||
TriVertex GetVertex(vertex_t *v1, double height) const
|
||||
{
|
||||
TriVertex v;
|
||||
v.x = (float)v1->fX();
|
||||
v.y = (float)v1->fY();
|
||||
v.z = (float)height;
|
||||
v.w = 1.0f;
|
||||
v.u = GetU(v.x, v.y);
|
||||
v.v = GetV(v.x, v.y);
|
||||
return v;
|
||||
}
|
||||
|
||||
private:
|
||||
float GetU(float x, float y) const { return (xOffs + x * cosine - y * sine) * xscale; }
|
||||
float GetV(float x, float y) const { return (yOffs - x * sine - y * cosine) * yscale; }
|
||||
|
||||
float xscale;
|
||||
float yscale;
|
||||
float cosine;
|
||||
float sine;
|
||||
float xOffs, yOffs;
|
||||
};
|
||||
|
||||
class RenderPolyPlane
|
||||
{
|
||||
public:
|
||||
static void RenderPlanes(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t ceilingSubsectorDepth, uint32_t floorSubsectorDepth, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals);
|
||||
static void RenderPlanes(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals);
|
||||
|
||||
private:
|
||||
struct UVTransform
|
||||
{
|
||||
UVTransform(const FTransform &transform, FTexture *tex);
|
||||
|
||||
float GetU(float x, float y) const;
|
||||
float GetV(float x, float y) const;
|
||||
|
||||
float xscale;
|
||||
float yscale;
|
||||
float cosine;
|
||||
float sine;
|
||||
float xOffs, yOffs;
|
||||
};
|
||||
|
||||
void Render3DFloor(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, F3DFloor *fakefloor);
|
||||
void Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals);
|
||||
TriVertex PlaneVertex(vertex_t *v1, double height, const UVTransform &transform);
|
||||
void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals);
|
||||
void RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, sector_t *frontsector, FSectorPortal *portal, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight, const PolyPlaneUVTransform &transform);
|
||||
};
|
||||
|
||||
class Render3DFloorPlane
|
||||
{
|
||||
public:
|
||||
static void RenderPlanes(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, uint32_t subsectorDepth, std::vector<PolyTranslucentObject *> &translucentObjects);
|
||||
|
||||
void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane);
|
||||
|
||||
subsector_t *sub = nullptr;
|
||||
uint32_t stencilValue = 0;
|
||||
bool ceiling = false;
|
||||
F3DFloor *fakeFloor = nullptr;
|
||||
bool Masked = false;
|
||||
bool Additive = false;
|
||||
double Alpha = 1.0;
|
||||
};
|
||||
|
||||
class PolyTranslucent3DFloorPlane : public PolyTranslucentObject
|
||||
{
|
||||
public:
|
||||
PolyTranslucent3DFloorPlane(Render3DFloorPlane plane, uint32_t subsectorDepth) : PolyTranslucentObject(subsectorDepth, 1e7), plane(plane) { }
|
||||
|
||||
void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &portalPlane) override
|
||||
{
|
||||
plane.Render(thread, worldToClip, portalPlane);
|
||||
}
|
||||
|
||||
Render3DFloorPlane plane;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Handling drawing a player sprite
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -35,7 +35,7 @@ EXTERN_CVAR(Bool, r_deathcamera)
|
|||
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor)
|
||||
EXTERN_CVAR(Bool, r_shadercolormaps)
|
||||
|
||||
void RenderPolyPlayerSprites::Render()
|
||||
void RenderPolyPlayerSprites::Render(PolyRenderThread *thread)
|
||||
{
|
||||
// This code cannot be moved directly to RenderRemainingSprites because the engine
|
||||
// draws the canvas textures between this call and the final call to RenderRemainingSprites..
|
||||
|
@ -143,7 +143,7 @@ void RenderPolyPlayerSprites::Render()
|
|||
|
||||
if ((psp->GetID() != PSP_TARGETCENTER || CrosshairImage == nullptr) && psp->GetCaller() != nullptr)
|
||||
{
|
||||
RenderSprite(psp, viewpoint.camera, bobx, boby, wx, wy, viewpoint.TicFrac, spriteshade, basecolormap, foggy);
|
||||
RenderSprite(thread, psp, viewpoint.camera, bobx, boby, wx, wy, viewpoint.TicFrac, spriteshade, basecolormap, foggy);
|
||||
}
|
||||
|
||||
psp = psp->GetNext();
|
||||
|
@ -180,7 +180,7 @@ void RenderPolyPlayerSprites::RenderRemainingSprites()
|
|||
AcceleratedSprites.Clear();
|
||||
}
|
||||
|
||||
void RenderPolyPlayerSprites::RenderSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac, int spriteshade, FDynamicColormap *basecolormap, bool foggy)
|
||||
void RenderPolyPlayerSprites::RenderSprite(PolyRenderThread *thread, DPSprite *pspr, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac, int spriteshade, FDynamicColormap *basecolormap, bool foggy)
|
||||
{
|
||||
double tx;
|
||||
int x1;
|
||||
|
@ -242,7 +242,7 @@ void RenderPolyPlayerSprites::RenderSprite(DPSprite *pspr, AActor *owner, float
|
|||
sy += wy;
|
||||
}
|
||||
|
||||
double yaspectMul = 1.2;// 320.0 * SCREENHEIGHT / (r_Yaspect * SCREENWIDTH);
|
||||
double yaspectMul = 1.2 * ((double)SCREENHEIGHT / SCREENWIDTH) * r_viewwindow.WidescreenRatio;
|
||||
|
||||
double pspritexscale = viewwindow.centerxwide / 160.0;
|
||||
double pspriteyscale = pspritexscale * yaspectMul;
|
||||
|
@ -454,7 +454,7 @@ void RenderPolyPlayerSprites::RenderSprite(DPSprite *pspr, AActor *owner, float
|
|||
}
|
||||
}
|
||||
|
||||
vis.Render();
|
||||
vis.Render(thread);
|
||||
}
|
||||
|
||||
fixed_t RenderPolyPlayerSprites::LightLevelToShade(int lightlevel, bool foggy)
|
||||
|
@ -475,7 +475,7 @@ fixed_t RenderPolyPlayerSprites::LightLevelToShade(int lightlevel, bool foggy)
|
|||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PolyNoAccelPlayerSprite::Render()
|
||||
void PolyNoAccelPlayerSprite::Render(PolyRenderThread *thread)
|
||||
{
|
||||
if (xscale == 0 || fabs(yscale) < (1.0f / 32000.0f))
|
||||
{ // scaled to 0; can't see
|
||||
|
@ -498,7 +498,7 @@ void PolyNoAccelPlayerSprite::Render()
|
|||
y1 = centerY - texturemid * yscale;
|
||||
y2 = y1 + pic->GetHeight() * yscale;
|
||||
}
|
||||
args.Draw(x1, x2, y1, y2, 0.0f, 1.0f, 0.0f, 1.0f);
|
||||
args.Draw(thread, x1, x2, y1, y2, 0.0f, 1.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Handling drawing a player sprite
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -61,7 +61,7 @@ public:
|
|||
|
||||
short renderflags = 0;
|
||||
|
||||
void Render();
|
||||
void Render(PolyRenderThread *thread);
|
||||
};
|
||||
|
||||
class PolyHWAccelPlayerSprite
|
||||
|
@ -90,11 +90,11 @@ public:
|
|||
class RenderPolyPlayerSprites
|
||||
{
|
||||
public:
|
||||
void Render();
|
||||
void Render(PolyRenderThread *thread);
|
||||
void RenderRemainingSprites();
|
||||
|
||||
private:
|
||||
void RenderSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac, int spriteshade, FDynamicColormap *basecolormap, bool foggy);
|
||||
void RenderSprite(PolyRenderThread *thread, DPSprite *pspr, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac, int spriteshade, FDynamicColormap *basecolormap, bool foggy);
|
||||
static fixed_t LightLevelToShade(int lightlevel, bool foggy);
|
||||
|
||||
enum { BASEXCENTER = 160 };
|
||||
|
|
|
@ -68,7 +68,7 @@ void PolyDrawSectorPortal::Render(int portalDepth)
|
|||
|
||||
PolyClipPlane portalPlane(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
RenderPortal.SetViewpoint(worldToClip, portalPlane, StencilValue);
|
||||
RenderPortal.SetPortalSegments(Segments);
|
||||
//RenderPortal.SetPortalSegments(Segments);
|
||||
RenderPortal.Render(portalDepth);
|
||||
|
||||
RestoreGlobals();
|
||||
|
@ -202,7 +202,7 @@ void PolyDrawLinePortal::Render(int portalDepth)
|
|||
|
||||
RenderPortal.LastPortalLine = clipLine;
|
||||
RenderPortal.SetViewpoint(worldToClip, portalPlane, StencilValue);
|
||||
RenderPortal.SetPortalSegments(Segments);
|
||||
//RenderPortal.SetPortalSegments(Segments);
|
||||
RenderPortal.Render(portalDepth);
|
||||
|
||||
RestoreGlobals();
|
||||
|
|
|
@ -26,11 +26,10 @@
|
|||
|
||||
struct PolyPortalVertexRange
|
||||
{
|
||||
PolyPortalVertexRange(const TriVertex *vertices, int count, bool ccw, uint32_t subsectorDepth) : Vertices(vertices), Count(count), Ccw(ccw), SubsectorDepth(subsectorDepth) { }
|
||||
PolyPortalVertexRange(const TriVertex *vertices, int count, bool ccw) : Vertices(vertices), Count(count), Ccw(ccw) { }
|
||||
const TriVertex *Vertices;
|
||||
int Count;
|
||||
bool Ccw;
|
||||
uint32_t SubsectorDepth;
|
||||
};
|
||||
|
||||
class PolyPortalSegment
|
||||
|
@ -51,7 +50,7 @@ public:
|
|||
FSectorPortal *Portal = nullptr;
|
||||
uint32_t StencilValue = 0;
|
||||
std::vector<PolyPortalVertexRange> Shape;
|
||||
std::vector<PolyPortalSegment> Segments;
|
||||
//std::vector<PolyPortalSegment> Segments;
|
||||
|
||||
private:
|
||||
void SaveGlobals();
|
||||
|
@ -81,7 +80,7 @@ public:
|
|||
line_t *Mirror = nullptr;
|
||||
uint32_t StencilValue = 0;
|
||||
std::vector<PolyPortalVertexRange> Shape;
|
||||
std::vector<PolyPortalSegment> Segments;
|
||||
//std::vector<PolyPortalSegment> Segments;
|
||||
|
||||
private:
|
||||
void SaveGlobals();
|
||||
|
|
|
@ -26,9 +26,14 @@
|
|||
#include "p_maputl.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "polyrenderer/scene/poly_scene.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_scene.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/scene/poly_wall.h"
|
||||
#include "polyrenderer/scene/poly_wallsprite.h"
|
||||
#include "polyrenderer/scene/poly_plane.h"
|
||||
#include "polyrenderer/scene/poly_particle.h"
|
||||
#include "polyrenderer/scene/poly_sprite.h"
|
||||
|
||||
EXTERN_CVAR(Int, r_portal_recursions)
|
||||
|
||||
|
@ -49,100 +54,48 @@ void RenderPolyScene::SetViewpoint(const TriMatrix &worldToClip, const PolyClipP
|
|||
PortalPlane = portalPlane;
|
||||
}
|
||||
|
||||
void RenderPolyScene::SetPortalSegments(const std::vector<PolyPortalSegment> &segments)
|
||||
{
|
||||
if (!segments.empty())
|
||||
{
|
||||
Cull.ClearSolidSegments();
|
||||
for (const auto &segment : segments)
|
||||
{
|
||||
Cull.MarkSegmentCulled(segment.Start, segment.End);
|
||||
}
|
||||
Cull.InvertSegments();
|
||||
PortalSegmentsAdded = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
PortalSegmentsAdded = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyScene::Render(int portalDepth)
|
||||
{
|
||||
ClearBuffers();
|
||||
if (!PortalSegmentsAdded)
|
||||
Cull.ClearSolidSegments();
|
||||
Cull.MarkViewFrustum();
|
||||
PolyRenderThread *thread = PolyRenderer::Instance()->Threads.MainThread();
|
||||
|
||||
SectorPortals.clear();
|
||||
LinePortals.clear();
|
||||
Cull.CullScene(WorldToClip, PortalPlane);
|
||||
Cull.ClearSolidSegments();
|
||||
RenderSectors();
|
||||
RenderPortals(portalDepth);
|
||||
}
|
||||
|
||||
void RenderPolyScene::ClearBuffers()
|
||||
{
|
||||
SeenSectors.clear();
|
||||
SubsectorDepths.clear();
|
||||
TranslucentObjects.clear();
|
||||
SectorPortals.clear();
|
||||
LinePortals.clear();
|
||||
NextSubsectorDepth = 0;
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderSectors()
|
||||
{
|
||||
int count = (int)Cull.PvsSectors.size();
|
||||
PolyRenderThread *mainthread = PolyRenderer::Instance()->Threads.MainThread();
|
||||
|
||||
int totalcount = (int)Cull.PvsSectors.size();
|
||||
auto subsectors = Cull.PvsSectors.data();
|
||||
|
||||
int nextCeilingZChange = 0;
|
||||
int nextFloorZChange = 0;
|
||||
uint32_t ceilingSubsectorDepth = 0;
|
||||
uint32_t floorSubsectorDepth = 0;
|
||||
TranslucentObjects.resize(PolyRenderer::Instance()->Threads.NumThreads());
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
PolyRenderer::Instance()->Threads.RenderThreadSlices(totalcount, [&](PolyRenderThread *thread)
|
||||
{
|
||||
// The software renderer only updates the clipping if the sector height changes.
|
||||
// Find the subsector depths for when that happens.
|
||||
if (i == nextCeilingZChange)
|
||||
{
|
||||
double z = subsectors[i]->sector->ceilingplane.Zat0();
|
||||
nextCeilingZChange++;
|
||||
while (nextCeilingZChange < count)
|
||||
{
|
||||
double nextZ = subsectors[nextCeilingZChange]->sector->ceilingplane.Zat0();
|
||||
if (nextZ > z)
|
||||
break;
|
||||
z = nextZ;
|
||||
nextCeilingZChange++;
|
||||
}
|
||||
ceilingSubsectorDepth = NextSubsectorDepth + nextCeilingZChange - i - 1;
|
||||
}
|
||||
if (i == nextFloorZChange)
|
||||
{
|
||||
double z = subsectors[i]->sector->floorplane.Zat0();
|
||||
nextFloorZChange++;
|
||||
while (nextFloorZChange < count)
|
||||
{
|
||||
double nextZ = subsectors[nextFloorZChange]->sector->floorplane.Zat0();
|
||||
if (nextZ < z)
|
||||
break;
|
||||
z = nextZ;
|
||||
nextFloorZChange++;
|
||||
}
|
||||
floorSubsectorDepth = NextSubsectorDepth + nextFloorZChange - i - 1;
|
||||
}
|
||||
TranslucentObjects[thread->ThreadIndex].clear();
|
||||
|
||||
RenderSubsector(subsectors[i], ceilingSubsectorDepth, floorSubsectorDepth);
|
||||
}
|
||||
int start = thread->Start;
|
||||
int end = thread->End;
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
RenderSubsector(thread, subsectors[i], i);
|
||||
}
|
||||
}, [&](PolyRenderThread *thread)
|
||||
{
|
||||
const auto &objects = TranslucentObjects[thread->ThreadIndex];
|
||||
TranslucentObjects[0].insert(TranslucentObjects[0].end(), objects.begin(), objects.end());
|
||||
});
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderSubsector(subsector_t *sub, uint32_t ceilingSubsectorDepth, uint32_t floorSubsectorDepth)
|
||||
void RenderPolyScene::RenderSubsector(PolyRenderThread *thread, subsector_t *sub, uint32_t subsectorDepth)
|
||||
{
|
||||
sector_t *frontsector = sub->sector;
|
||||
frontsector->MoreFlags |= SECF_DRAWN;
|
||||
|
||||
uint32_t subsectorDepth = NextSubsectorDepth++;
|
||||
|
||||
bool mainBSP = sub->polys == nullptr;
|
||||
|
||||
if (sub->polys)
|
||||
|
@ -161,43 +114,43 @@ void RenderPolyScene::RenderSubsector(subsector_t *sub, uint32_t ceilingSubsecto
|
|||
|
||||
if (sub->BSP->Nodes.Size() == 0)
|
||||
{
|
||||
RenderPolySubsector(&sub->BSP->Subsectors[0], subsectorDepth, frontsector);
|
||||
RenderPolySubsector(thread, &sub->BSP->Subsectors[0], subsectorDepth, frontsector);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderPolyNode(&sub->BSP->Nodes.Last(), subsectorDepth, frontsector);
|
||||
RenderPolyNode(thread, &sub->BSP->Nodes.Last(), subsectorDepth, frontsector);
|
||||
}
|
||||
|
||||
Render3DFloorPlane::RenderPlanes(thread, WorldToClip, PortalPlane, sub, StencilValue, subsectorDepth, TranslucentObjects[thread->ThreadIndex]);
|
||||
RenderPolyPlane::RenderPlanes(thread, WorldToClip, PortalPlane, sub, StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, SectorPortals);
|
||||
}
|
||||
else
|
||||
{
|
||||
Render3DFloorPlane::RenderPlanes(thread, WorldToClip, PortalPlane, sub, StencilValue, subsectorDepth, TranslucentObjects[thread->ThreadIndex]);
|
||||
RenderPolyPlane::RenderPlanes(thread, WorldToClip, PortalPlane, sub, StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, SectorPortals);
|
||||
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
RenderLine(sub, line, frontsector, subsectorDepth);
|
||||
if (Cull.IsLineSegVisible(subsectorDepth, i))
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
RenderLine(thread, sub, line, frontsector, subsectorDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sub->sector->CenterFloor() != sub->sector->CenterCeiling())
|
||||
{
|
||||
RenderPolyPlane::RenderPlanes(WorldToClip, PortalPlane, Cull, sub, ceilingSubsectorDepth, floorSubsectorDepth, StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, SectorPortals);
|
||||
}
|
||||
|
||||
if (mainBSP)
|
||||
{
|
||||
RenderMemory &memory = PolyRenderer::Instance()->FrameMemory;
|
||||
int subsectorIndex = sub->Index();
|
||||
for (int i = ParticlesInSubsec[subsectorIndex]; i != NO_PARTICLE; i = Particles[i].snext)
|
||||
{
|
||||
particle_t *particle = Particles + i;
|
||||
TranslucentObjects.push_back(memory.NewObject<PolyTranslucentObject>(particle, sub, subsectorDepth));
|
||||
TranslucentObjects[thread->ThreadIndex].push_back(thread->FrameMemory->NewObject<PolyTranslucentParticle>(particle, sub, subsectorDepth, StencilValue));
|
||||
}
|
||||
}
|
||||
|
||||
SeenSectors.insert(sub->sector);
|
||||
SubsectorDepths[sub] = subsectorDepth;
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderPolyNode(void *node, uint32_t subsectorDepth, sector_t *frontsector)
|
||||
void RenderPolyScene::RenderPolyNode(PolyRenderThread *thread, void *node, uint32_t subsectorDepth, sector_t *frontsector)
|
||||
{
|
||||
while (!((size_t)node & 1)) // Keep going until found a subsector
|
||||
{
|
||||
|
@ -207,7 +160,7 @@ void RenderPolyScene::RenderPolyNode(void *node, uint32_t subsectorDepth, sector
|
|||
int side = PointOnSide(PolyRenderer::Instance()->Viewpoint.Pos, bsp);
|
||||
|
||||
// Recursively divide front space (toward the viewer).
|
||||
RenderPolyNode(bsp->children[side], subsectorDepth, frontsector);
|
||||
RenderPolyNode(thread, bsp->children[side], subsectorDepth, frontsector);
|
||||
|
||||
// Possibly divide back space (away from the viewer).
|
||||
side ^= 1;
|
||||
|
@ -220,10 +173,10 @@ void RenderPolyScene::RenderPolyNode(void *node, uint32_t subsectorDepth, sector
|
|||
}
|
||||
|
||||
subsector_t *sub = (subsector_t *)((uint8_t *)node - 1);
|
||||
RenderPolySubsector(sub, subsectorDepth, frontsector);
|
||||
RenderPolySubsector(thread, sub, subsectorDepth, frontsector);
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderPolySubsector(subsector_t *sub, uint32_t subsectorDepth, sector_t *frontsector)
|
||||
void RenderPolyScene::RenderPolySubsector(PolyRenderThread *thread, subsector_t *sub, uint32_t subsectorDepth, sector_t *frontsector)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
|
@ -238,11 +191,6 @@ void RenderPolyScene::RenderPolySubsector(subsector_t *sub, uint32_t subsectorDe
|
|||
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
|
||||
continue;
|
||||
|
||||
// Cull wall if not visible
|
||||
angle_t angle1, angle2;
|
||||
if (!Cull.GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2))
|
||||
continue;
|
||||
|
||||
// Tell automap we saw this
|
||||
if (!PolyRenderer::Instance()->DontMapLines && line->linedef)
|
||||
{
|
||||
|
@ -250,11 +198,7 @@ void RenderPolyScene::RenderPolySubsector(subsector_t *sub, uint32_t subsectorDe
|
|||
sub->flags |= SSECF_DRAWN;
|
||||
}
|
||||
|
||||
// Render wall, and update culling info if its an occlusion blocker
|
||||
if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals, LastPortalLine))
|
||||
{
|
||||
Cull.MarkSegmentCulled(angle1, angle2);
|
||||
}
|
||||
RenderPolyWall::RenderLine(thread, WorldToClip, PortalPlane, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects[thread->ThreadIndex], LinePortals, LastPortalLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -264,22 +208,21 @@ int RenderPolyScene::PointOnSide(const DVector2 &pos, const node_t *node)
|
|||
return DMulScale32(FLOAT2FIXED(pos.Y) - node->y, node->dx, node->x - FLOAT2FIXED(pos.X), node->dy) > 0;
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderSprite(AActor *thing, double sortDistance, const DVector2 &left, const DVector2 &right)
|
||||
void RenderPolyScene::RenderSprite(PolyRenderThread *thread, AActor *thing, double sortDistance, const DVector2 &left, const DVector2 &right)
|
||||
{
|
||||
if (level.nodes.Size() == 0)
|
||||
{
|
||||
subsector_t *sub = &level.subsectors[0];
|
||||
auto it = SubsectorDepths.find(sub);
|
||||
if (it != SubsectorDepths.end())
|
||||
TranslucentObjects.push_back(PolyRenderer::Instance()->FrameMemory.NewObject<PolyTranslucentObject>(thing, sub, it->second, sortDistance, 0.0f, 1.0f));
|
||||
if (Cull.SubsectorDepths[sub->Index()] != 0xffffffff)
|
||||
TranslucentObjects[thread->ThreadIndex].push_back(thread->FrameMemory->NewObject<PolyTranslucentThing>(thing, sub, Cull.SubsectorDepths[sub->Index()], sortDistance, 0.0f, 1.0f, StencilValue));
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderSprite(thing, sortDistance, left, right, 0.0, 1.0, level.HeadNode());
|
||||
RenderSprite(thread, thing, sortDistance, left, right, 0.0, 1.0, level.HeadNode());
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderSprite(AActor *thing, double sortDistance, DVector2 left, DVector2 right, double t1, double t2, void *node)
|
||||
void RenderPolyScene::RenderSprite(PolyRenderThread *thread, AActor *thing, double sortDistance, DVector2 left, DVector2 right, double t1, double t2, void *node)
|
||||
{
|
||||
while (!((size_t)node & 1)) // Keep going until found a subsector
|
||||
{
|
||||
|
@ -301,7 +244,7 @@ void RenderPolyScene::RenderSprite(AActor *thing, double sortDistance, DVector2
|
|||
DVector2 mid = left * (1.0 - t) + right * t;
|
||||
double tmid = t1 * (1.0 - t) + t2 * t;
|
||||
|
||||
RenderSprite(thing, sortDistance, mid, right, tmid, t2, bsp->children[sideRight]);
|
||||
RenderSprite(thread, thing, sortDistance, mid, right, tmid, t2, bsp->children[sideRight]);
|
||||
right = mid;
|
||||
t2 = tmid;
|
||||
}
|
||||
|
@ -310,26 +253,12 @@ void RenderPolyScene::RenderSprite(AActor *thing, double sortDistance, DVector2
|
|||
|
||||
subsector_t *sub = (subsector_t *)((uint8_t *)node - 1);
|
||||
|
||||
auto it = SubsectorDepths.find(sub);
|
||||
if (it != SubsectorDepths.end())
|
||||
TranslucentObjects.push_back(PolyRenderer::Instance()->FrameMemory.NewObject<PolyTranslucentObject>(thing, sub, it->second, sortDistance, (float)t1, (float)t2));
|
||||
if (Cull.SubsectorDepths[sub->Index()] != 0xffffffff)
|
||||
TranslucentObjects[thread->ThreadIndex].push_back(thread->FrameMemory->NewObject<PolyTranslucentThing>(thing, sub, Cull.SubsectorDepths[sub->Index()], sortDistance, (float)t1, (float)t2, StencilValue));
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderLine(subsector_t *sub, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth)
|
||||
void RenderPolyScene::RenderLine(PolyRenderThread *thread, subsector_t *sub, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
// Reject lines not facing viewer
|
||||
DVector2 pt1 = line->v1->fPos() - viewpoint.Pos;
|
||||
DVector2 pt2 = line->v2->fPos() - viewpoint.Pos;
|
||||
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
|
||||
return;
|
||||
|
||||
// Cull wall if not visible
|
||||
angle_t angle1, angle2;
|
||||
if (!Cull.GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2))
|
||||
return;
|
||||
|
||||
// Tell automap we saw this
|
||||
if (!PolyRenderer::Instance()->DontMapLines && line->linedef)
|
||||
{
|
||||
|
@ -338,27 +267,23 @@ void RenderPolyScene::RenderLine(subsector_t *sub, seg_t *line, sector_t *fronts
|
|||
}
|
||||
|
||||
// Render 3D floor sides
|
||||
if (line->backsector && frontsector->e && line->backsector->e->XFloor.ffloors.Size())
|
||||
if (line->sidedef && line->backsector && line->backsector->e && line->backsector->e->XFloor.ffloors.Size())
|
||||
{
|
||||
for (unsigned int i = 0; i < line->backsector->e->XFloor.ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *fakeFloor = line->backsector->e->XFloor.ffloors[i];
|
||||
if (!(fakeFloor->flags & FF_EXISTS)) continue;
|
||||
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
|
||||
if (!fakeFloor->model) continue;
|
||||
RenderPolyWall::Render3DFloorLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, fakeFloor, TranslucentObjects);
|
||||
RenderPolyWall::Render3DFloorLine(thread, WorldToClip, PortalPlane, line, frontsector, subsectorDepth, StencilValue, fakeFloor, TranslucentObjects[thread->ThreadIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
// Render wall, and update culling info if its an occlusion blocker
|
||||
if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals, LastPortalLine))
|
||||
{
|
||||
Cull.MarkSegmentCulled(angle1, angle2);
|
||||
}
|
||||
RenderPolyWall::RenderLine(thread, WorldToClip, PortalPlane, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects[thread->ThreadIndex], LinePortals, LastPortalLine);
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderPortals(int portalDepth)
|
||||
{
|
||||
PolyRenderThread *thread = PolyRenderer::Instance()->Threads.MainThread();
|
||||
|
||||
bool foggy = false;
|
||||
if (portalDepth < r_portal_recursions)
|
||||
{
|
||||
|
@ -374,7 +299,7 @@ void RenderPolyScene::RenderPortals(int portalDepth)
|
|||
args.SetTransform(&WorldToClip);
|
||||
args.SetLight(&NormalLight, 255, PolyRenderer::Instance()->Light.WallGlobVis(foggy), true);
|
||||
args.SetColor(0, 0);
|
||||
args.SetClipPlane(PortalPlane);
|
||||
args.SetClipPlane(0, PortalPlane);
|
||||
args.SetStyle(TriBlendMode::FillOpaque);
|
||||
|
||||
for (auto &portal : SectorPortals)
|
||||
|
@ -384,8 +309,7 @@ void RenderPolyScene::RenderPortals(int portalDepth)
|
|||
for (const auto &verts : portal->Shape)
|
||||
{
|
||||
args.SetFaceCullCCW(verts.Ccw);
|
||||
args.SetSubsectorDepth(verts.SubsectorDepth);
|
||||
args.DrawArray(verts.Vertices, verts.Count, PolyDrawMode::TriangleFan);
|
||||
args.DrawArray(thread, verts.Vertices, verts.Count, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -396,8 +320,7 @@ void RenderPolyScene::RenderPortals(int portalDepth)
|
|||
for (const auto &verts : portal->Shape)
|
||||
{
|
||||
args.SetFaceCullCCW(verts.Ccw);
|
||||
args.SetSubsectorDepth(verts.SubsectorDepth);
|
||||
args.DrawArray(verts.Vertices, verts.Count, PolyDrawMode::TriangleFan);
|
||||
args.DrawArray(thread, verts.Vertices, verts.Count, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -405,6 +328,8 @@ void RenderPolyScene::RenderPortals(int portalDepth)
|
|||
|
||||
void RenderPolyScene::RenderTranslucent(int portalDepth)
|
||||
{
|
||||
PolyRenderThread *thread = PolyRenderer::Instance()->Threads.MainThread();
|
||||
|
||||
if (portalDepth < r_portal_recursions)
|
||||
{
|
||||
for (auto it = SectorPortals.rbegin(); it != SectorPortals.rend(); ++it)
|
||||
|
@ -416,13 +341,12 @@ void RenderPolyScene::RenderTranslucent(int portalDepth)
|
|||
args.SetTransform(&WorldToClip);
|
||||
args.SetStencilTestValue(portal->StencilValue + 1);
|
||||
args.SetWriteStencil(true, StencilValue + 1);
|
||||
args.SetClipPlane(PortalPlane);
|
||||
args.SetClipPlane(0, PortalPlane);
|
||||
for (const auto &verts : portal->Shape)
|
||||
{
|
||||
args.SetFaceCullCCW(verts.Ccw);
|
||||
args.SetSubsectorDepth(verts.SubsectorDepth);
|
||||
args.SetWriteColor(false);
|
||||
args.DrawArray(verts.Vertices, verts.Count, PolyDrawMode::TriangleFan);
|
||||
args.DrawArray(thread, verts.Vertices, verts.Count, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -435,19 +359,18 @@ void RenderPolyScene::RenderTranslucent(int portalDepth)
|
|||
args.SetTransform(&WorldToClip);
|
||||
args.SetStencilTestValue(portal->StencilValue + 1);
|
||||
args.SetWriteStencil(true, StencilValue + 1);
|
||||
args.SetClipPlane(PortalPlane);
|
||||
args.SetClipPlane(0, PortalPlane);
|
||||
for (const auto &verts : portal->Shape)
|
||||
{
|
||||
args.SetFaceCullCCW(verts.Ccw);
|
||||
args.SetSubsectorDepth(verts.SubsectorDepth);
|
||||
args.SetWriteColor(false);
|
||||
args.DrawArray(verts.Vertices, verts.Count, PolyDrawMode::TriangleFan);
|
||||
args.DrawArray(thread, verts.Vertices, verts.Count, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
for (sector_t *sector : SeenSectors)
|
||||
for (sector_t *sector : Cull.SeenSectors)
|
||||
{
|
||||
for (AActor *thing = sector->thinglist; thing != nullptr; thing = thing->snext)
|
||||
{
|
||||
|
@ -455,33 +378,18 @@ void RenderPolyScene::RenderTranslucent(int portalDepth)
|
|||
if (!RenderPolySprite::GetLine(thing, left, right))
|
||||
continue;
|
||||
double distanceSquared = (thing->Pos() - viewpoint.Pos).LengthSquared();
|
||||
RenderSprite(thing, distanceSquared, left, right);
|
||||
RenderSprite(thread, thing, distanceSquared, left, right);
|
||||
}
|
||||
}
|
||||
|
||||
std::stable_sort(TranslucentObjects.begin(), TranslucentObjects.end(), [](auto a, auto b) { return *a < *b; });
|
||||
std::stable_sort(TranslucentObjects[0].begin(), TranslucentObjects[0].end(), [](auto a, auto b) { return *a < *b; });
|
||||
|
||||
for (auto it = TranslucentObjects.rbegin(); it != TranslucentObjects.rend(); ++it)
|
||||
for (auto it = TranslucentObjects[0].rbegin(); it != TranslucentObjects[0].rend(); ++it)
|
||||
{
|
||||
PolyTranslucentObject *obj = *it;
|
||||
if (obj->particle)
|
||||
{
|
||||
RenderPolyParticle spr;
|
||||
spr.Render(WorldToClip, PortalPlane, obj->particle, obj->sub, obj->subsectorDepth, StencilValue + 1);
|
||||
}
|
||||
else if (!obj->thing)
|
||||
{
|
||||
obj->wall.Render(WorldToClip, PortalPlane, Cull);
|
||||
}
|
||||
else if ((obj->thing->renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE)
|
||||
{
|
||||
RenderPolyWallSprite wallspr;
|
||||
wallspr.Render(WorldToClip, PortalPlane, obj->thing, obj->sub, obj->subsectorDepth, StencilValue + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderPolySprite spr;
|
||||
spr.Render(WorldToClip, PortalPlane, obj->thing, obj->sub, obj->subsectorDepth, StencilValue + 1, obj->SpriteLeft, obj->SpriteRight);
|
||||
}
|
||||
obj->Render(thread, WorldToClip, PortalPlane);
|
||||
obj->~PolyTranslucentObject();
|
||||
}
|
||||
|
||||
TranslucentObjects[0].clear();
|
||||
}
|
||||
|
|
|
@ -29,38 +29,24 @@
|
|||
#include "doomdata.h"
|
||||
#include "r_utility.h"
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include "poly_wall.h"
|
||||
#include "poly_sprite.h"
|
||||
#include "poly_wallsprite.h"
|
||||
#include "poly_playersprite.h"
|
||||
#include "poly_particle.h"
|
||||
#include "poly_plane.h"
|
||||
#include "poly_cull.h"
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
class PolyTranslucentObject
|
||||
{
|
||||
public:
|
||||
PolyTranslucentObject(particle_t *particle, subsector_t *sub, uint32_t subsectorDepth) : particle(particle), sub(sub), subsectorDepth(subsectorDepth) { }
|
||||
PolyTranslucentObject(AActor *thing, subsector_t *sub, uint32_t subsectorDepth, double dist, float t1, float t2) : thing(thing), sub(sub), subsectorDepth(subsectorDepth), DistanceSquared(dist), SpriteLeft(t1), SpriteRight(t2) { }
|
||||
PolyTranslucentObject(RenderPolyWall wall) : wall(wall), subsectorDepth(wall.SubsectorDepth), DistanceSquared(1.e6) { }
|
||||
PolyTranslucentObject(uint32_t subsectorDepth = 0, double distanceSquared = 0.0) : subsectorDepth(subsectorDepth), DistanceSquared(distanceSquared) { }
|
||||
virtual ~PolyTranslucentObject() { }
|
||||
|
||||
virtual void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &portalPlane) = 0;
|
||||
|
||||
bool operator<(const PolyTranslucentObject &other) const
|
||||
{
|
||||
return subsectorDepth != other.subsectorDepth ? subsectorDepth < other.subsectorDepth : DistanceSquared < other.DistanceSquared;
|
||||
}
|
||||
|
||||
particle_t *particle = nullptr;
|
||||
AActor *thing = nullptr;
|
||||
subsector_t *sub = nullptr;
|
||||
|
||||
RenderPolyWall wall;
|
||||
|
||||
uint32_t subsectorDepth = 0;
|
||||
double DistanceSquared = 0.0;
|
||||
|
||||
float SpriteLeft = 0.0f, SpriteRight = 1.0f;
|
||||
uint32_t subsectorDepth;
|
||||
double DistanceSquared;
|
||||
};
|
||||
|
||||
class PolyDrawSectorPortal;
|
||||
|
@ -74,7 +60,6 @@ public:
|
|||
RenderPolyScene();
|
||||
~RenderPolyScene();
|
||||
void SetViewpoint(const TriMatrix &worldToClip, const PolyClipPlane &portalPlane, uint32_t stencilValue);
|
||||
void SetPortalSegments(const std::vector<PolyPortalSegment> &segments);
|
||||
void Render(int portalDepth);
|
||||
void RenderTranslucent(int portalDepth);
|
||||
|
||||
|
@ -83,28 +68,24 @@ public:
|
|||
line_t *LastPortalLine = nullptr;
|
||||
|
||||
private:
|
||||
void ClearBuffers();
|
||||
void RenderPortals(int portalDepth);
|
||||
void RenderSectors();
|
||||
void RenderSubsector(subsector_t *sub, uint32_t ceilingSubsectorDepth, uint32_t floorSubsectorDepth);
|
||||
void RenderLine(subsector_t *sub, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth);
|
||||
void RenderSprite(AActor *thing, double sortDistance, const DVector2 &left, const DVector2 &right);
|
||||
void RenderSprite(AActor *thing, double sortDistance, DVector2 left, DVector2 right, double t1, double t2, void *node);
|
||||
void RenderSubsector(PolyRenderThread *thread, subsector_t *sub, uint32_t subsectorDepth);
|
||||
void RenderLine(PolyRenderThread *thread, subsector_t *sub, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth);
|
||||
void RenderSprite(PolyRenderThread *thread, AActor *thing, double sortDistance, const DVector2 &left, const DVector2 &right);
|
||||
void RenderSprite(PolyRenderThread *thread, AActor *thing, double sortDistance, DVector2 left, DVector2 right, double t1, double t2, void *node);
|
||||
|
||||
void RenderPolySubsector(subsector_t *sub, uint32_t subsectorDepth, sector_t *frontsector);
|
||||
void RenderPolyNode(void *node, uint32_t subsectorDepth, sector_t *frontsector);
|
||||
void RenderPolySubsector(PolyRenderThread *thread, subsector_t *sub, uint32_t subsectorDepth, sector_t *frontsector);
|
||||
void RenderPolyNode(PolyRenderThread *thread, void *node, uint32_t subsectorDepth, sector_t *frontsector);
|
||||
static int PointOnSide(const DVector2 &pos, const node_t *node);
|
||||
|
||||
TriMatrix WorldToClip;
|
||||
PolyClipPlane PortalPlane;
|
||||
uint32_t StencilValue = 0;
|
||||
PolyCull Cull;
|
||||
uint32_t NextSubsectorDepth = 0;
|
||||
std::set<sector_t *> SeenSectors;
|
||||
std::unordered_map<subsector_t *, uint32_t> SubsectorDepths;
|
||||
std::vector<PolyTranslucentObject *> TranslucentObjects;
|
||||
bool PortalSegmentsAdded = false;
|
||||
|
||||
std::vector<std::vector<PolyTranslucentObject *>> TranslucentObjects;
|
||||
std::vector<std::unique_ptr<PolyDrawSectorPortal>> SectorPortals;
|
||||
std::vector<std::unique_ptr<PolyDrawLinePortal>> LinePortals;
|
||||
bool PortalSegmentsAdded = false;
|
||||
};
|
||||
|
|
|
@ -35,7 +35,7 @@ PolySkyDome::PolySkyDome()
|
|||
CreateDome();
|
||||
}
|
||||
|
||||
void PolySkyDome::Render(const TriMatrix &worldToClip)
|
||||
void PolySkyDome::Render(PolyRenderThread *thread, const TriMatrix &worldToClip)
|
||||
{
|
||||
#ifdef USE_GL_DOME_MATH
|
||||
TriMatrix modelMatrix = GLSkyMath();
|
||||
|
@ -83,14 +83,13 @@ void PolySkyDome::Render(const TriMatrix &worldToClip)
|
|||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(&NormalLight, 255, PolyRenderer::Instance()->Light.WallGlobVis(false), true);
|
||||
args.SetSubsectorDepth(RenderPolyScene::SkySubsectorDepth);
|
||||
args.SetTransform(&objectToClip);
|
||||
args.SetStencilTestValue(255);
|
||||
args.SetWriteStencil(true, 1);
|
||||
args.SetClipPlane(PolyClipPlane(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
args.SetClipPlane(0, PolyClipPlane(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
|
||||
RenderCapColorRow(args, mCurrentSetup.frontskytex, 0, false);
|
||||
RenderCapColorRow(args, mCurrentSetup.frontskytex, rc, true);
|
||||
RenderCapColorRow(thread, args, mCurrentSetup.frontskytex, 0, false);
|
||||
RenderCapColorRow(thread, args, mCurrentSetup.frontskytex, rc, true);
|
||||
|
||||
args.SetTexture(mCurrentSetup.frontskytex);
|
||||
|
||||
|
@ -101,20 +100,20 @@ void PolySkyDome::Render(const TriMatrix &worldToClip)
|
|||
|
||||
for (int i = 1; i <= mRows; i++)
|
||||
{
|
||||
RenderRow(args, i, topcapcolor, topcapindex);
|
||||
RenderRow(args, rc + i, bottomcapcolor, bottomcapindex);
|
||||
RenderRow(thread, args, i, topcapcolor, topcapindex);
|
||||
RenderRow(thread, args, rc + i, bottomcapcolor, bottomcapindex);
|
||||
}
|
||||
}
|
||||
|
||||
void PolySkyDome::RenderRow(PolyDrawArgs &args, int row, uint32_t capcolor, uint8_t capcolorindex)
|
||||
void PolySkyDome::RenderRow(PolyRenderThread *thread, PolyDrawArgs &args, int row, uint32_t capcolor, uint8_t capcolorindex)
|
||||
{
|
||||
args.SetFaceCullCCW(false);
|
||||
args.SetColor(capcolor, capcolorindex);
|
||||
args.SetStyle(TriBlendMode::Skycap);
|
||||
args.DrawArray(&mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], PolyDrawMode::TriangleStrip);
|
||||
args.DrawArray(thread, &mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], PolyDrawMode::TriangleStrip);
|
||||
}
|
||||
|
||||
void PolySkyDome::RenderCapColorRow(PolyDrawArgs &args, FTexture *skytex, int row, bool bottomCap)
|
||||
void PolySkyDome::RenderCapColorRow(PolyRenderThread *thread, PolyDrawArgs &args, FTexture *skytex, int row, bool bottomCap)
|
||||
{
|
||||
uint32_t solid = skytex->GetSkyCapColor(bottomCap);
|
||||
uint8_t palsolid = RGB32k.RGB[(RPART(solid) >> 3)][(GPART(solid) >> 3)][(BPART(solid) >> 3)];
|
||||
|
@ -122,7 +121,7 @@ void PolySkyDome::RenderCapColorRow(PolyDrawArgs &args, FTexture *skytex, int ro
|
|||
args.SetFaceCullCCW(bottomCap);
|
||||
args.SetColor(solid, palsolid);
|
||||
args.SetStyle(TriBlendMode::FillOpaque);
|
||||
args.DrawArray(&mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], PolyDrawMode::TriangleFan);
|
||||
args.DrawArray(thread, &mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], PolyDrawMode::TriangleFan);
|
||||
}
|
||||
|
||||
void PolySkyDome::CreateDome()
|
||||
|
|
|
@ -46,7 +46,7 @@ class PolySkyDome
|
|||
{
|
||||
public:
|
||||
PolySkyDome();
|
||||
void Render(const TriMatrix &worldToClip);
|
||||
void Render(PolyRenderThread *thread, const TriMatrix &worldToClip);
|
||||
|
||||
private:
|
||||
TArray<FVector2> mInitialUV;
|
||||
|
@ -58,8 +58,8 @@ private:
|
|||
void SkyVertex(int r, int c, bool yflip);
|
||||
void CreateSkyHemisphere(bool zflip);
|
||||
void CreateDome();
|
||||
void RenderRow(PolyDrawArgs &args, int row, uint32_t capcolor, uint8_t capcolorindex);
|
||||
void RenderCapColorRow(PolyDrawArgs &args, FTexture *skytex, int row, bool bottomCap);
|
||||
void RenderRow(PolyRenderThread *thread, PolyDrawArgs &args, int row, uint32_t capcolor, uint8_t capcolorindex);
|
||||
void RenderCapColorRow(PolyRenderThread *thread, PolyDrawArgs &args, FTexture *skytex, int row, bool bottomCap);
|
||||
|
||||
TriVertex SetVertexXYZ(float xx, float yy, float zz, float uu = 0, float vv = 0);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Handling drawing a sprite
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -28,11 +28,16 @@
|
|||
#include "poly_sprite.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
#include "r_data/r_vanillatrans.h"
|
||||
#include "actorinlines.h"
|
||||
|
||||
EXTERN_CVAR(Float, transsouls)
|
||||
EXTERN_CVAR(Int, r_drawfuzz)
|
||||
EXTERN_CVAR (Bool, r_debug_disable_vis_filter)
|
||||
EXTERN_CVAR(Int, gl_spriteclip)
|
||||
EXTERN_CVAR(Float, gl_sclipthreshold)
|
||||
EXTERN_CVAR(Float, gl_sclipfactor)
|
||||
extern uint32_t r_renderercaps;
|
||||
|
||||
bool RenderPolySprite::GetLine(AActor *thing, DVector2 &left, DVector2 &right)
|
||||
|
@ -67,15 +72,24 @@ bool RenderPolySprite::GetLine(AActor *thing, DVector2 &left, DVector2 &right)
|
|||
return true;
|
||||
}
|
||||
|
||||
void RenderPolySprite::Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, float t1, float t2)
|
||||
void RenderPolySprite::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t stencilValue, float t1, float t2)
|
||||
{
|
||||
DVector2 line[2];
|
||||
if (!GetLine(thing, line[0], line[1]))
|
||||
return;
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac);
|
||||
pos.Z += thing->GetBobOffset(viewpoint.TicFrac);
|
||||
DVector3 thingpos = thing->InterpolatedPosition(viewpoint.TicFrac);
|
||||
|
||||
DVector3 pos = thingpos;
|
||||
|
||||
uint32_t spritetype = (thing->renderflags & RF_SPRITETYPEMASK);
|
||||
|
||||
if (spritetype == RF_FACESPRITE)
|
||||
pos.Z -= thing->Floorclip;
|
||||
|
||||
if (thing->flags2 & MF2_FLOATBOB)
|
||||
pos.Z += thing->GetBobOffset(viewpoint.TicFrac);
|
||||
|
||||
bool flipTextureX = false;
|
||||
FTexture *tex = GetSpriteTexture(thing, flipTextureX);
|
||||
|
@ -85,26 +99,25 @@ void RenderPolySprite::Render(const TriMatrix &worldToClip, const PolyClipPlane
|
|||
DVector2 spriteScale = thing->Scale;
|
||||
double thingxscalemul = spriteScale.X / tex->Scale.X;
|
||||
double thingyscalemul = spriteScale.Y / tex->Scale.Y;
|
||||
double spriteHalfWidth = thingxscalemul * tex->GetWidth() * 0.5;
|
||||
double spriteHeight = thingyscalemul * tex->GetHeight();
|
||||
|
||||
if (flipTextureX)
|
||||
pos.X -= (tex->GetWidth() - tex->LeftOffset) * thingxscalemul;
|
||||
else
|
||||
pos.X -= tex->LeftOffset * thingxscalemul;
|
||||
|
||||
//pos.Z -= tex->TopOffset * thingyscalemul;
|
||||
pos.Z -= (tex->GetHeight() - tex->TopOffset) * thingyscalemul + thing->Floorclip;
|
||||
|
||||
double spriteHalfWidth = thingxscalemul * tex->GetWidth() * 0.5;
|
||||
double spriteHeight = thingyscalemul * tex->GetHeight();
|
||||
|
||||
pos.X += spriteHalfWidth;
|
||||
|
||||
pos.Z -= (tex->GetHeight() - tex->TopOffset) * thingyscalemul;
|
||||
pos.Z = PerformSpriteClipAdjustment(thing, thingpos, spriteHeight, pos.Z);
|
||||
|
||||
//double depth = 1.0;
|
||||
//visstyle_t visstyle = GetSpriteVisStyle(thing, depth);
|
||||
// Rumor has it that AlterWeaponSprite needs to be called with visstyle passed in somewhere around here..
|
||||
//R_SetColorMapLight(visstyle.BaseColormap, 0, visstyle.ColormapNum << FRACBITS);
|
||||
|
||||
TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(4);
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : viewpoint.extralight << 4;
|
||||
|
@ -142,20 +155,122 @@ void RenderPolySprite::Render(const TriMatrix &worldToClip, const PolyClipPlane
|
|||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(GetColorTable(sub->sector->Colormap, sub->sector->SpecialColors[sector_t::sprites], true), lightlevel, PolyRenderer::Instance()->Light.SpriteGlobVis(foggy), fullbrightSprite);
|
||||
args.SetSubsectorDepth(subsectorDepth);
|
||||
args.SetTransform(&worldToClip);
|
||||
args.SetFaceCullCCW(true);
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetWriteStencil(true, stencilValue);
|
||||
args.SetClipPlane(clipPlane);
|
||||
args.SetClipPlane(0, clipPlane);
|
||||
if ((thing->renderflags & RF_ZDOOMTRANS) && r_UseVanillaTransparency)
|
||||
args.SetStyle(LegacyRenderStyles[STYLE_Normal], 1.0f, thing->fillcolor, thing->Translation, tex, fullbrightSprite);
|
||||
else
|
||||
args.SetStyle(thing->RenderStyle, thing->Alpha, thing->fillcolor, thing->Translation, tex, fullbrightSprite);
|
||||
args.SetSubsectorDepthTest(true);
|
||||
args.SetWriteSubsectorDepth(false);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(false);
|
||||
args.SetWriteStencil(false);
|
||||
args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
|
||||
args.DrawArray(thread, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
|
||||
double RenderPolySprite::GetSpriteFloorZ(AActor *thing, const DVector2 &thingpos)
|
||||
{
|
||||
extsector_t::xfloor &x = thing->Sector->e->XFloor;
|
||||
for (unsigned int i = 0; i < x.ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *ff = x.ffloors[i];
|
||||
double floorh = ff->top.plane->ZatPoint(thingpos);
|
||||
if (floorh == thing->floorz)
|
||||
return floorh;
|
||||
}
|
||||
|
||||
if (thing->Sector->heightsec && !(thing->Sector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC))
|
||||
{
|
||||
if (thing->flags2&MF2_ONMOBJ && thing->floorz == thing->Sector->heightsec->floorplane.ZatPoint(thingpos))
|
||||
{
|
||||
return thing->floorz;
|
||||
}
|
||||
}
|
||||
|
||||
return thing->Sector->floorplane.ZatPoint(thing) - thing->Floorclip;
|
||||
}
|
||||
|
||||
double RenderPolySprite::GetSpriteCeilingZ(AActor *thing, const DVector2 &thingpos)
|
||||
{
|
||||
extsector_t::xfloor &x = thing->Sector->e->XFloor;
|
||||
for (unsigned int i = 0; i < x.ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *ff = x.ffloors[i];
|
||||
double ceilingh = ff->bottom.plane->ZatPoint(thingpos);
|
||||
if (ceilingh == thing->ceilingz)
|
||||
return ceilingh;
|
||||
}
|
||||
|
||||
if (thing->Sector->heightsec && !(thing->Sector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC))
|
||||
{
|
||||
if (thing->flags2&MF2_ONMOBJ && thing->ceilingz == thing->Sector->heightsec->ceilingplane.ZatPoint(thingpos))
|
||||
{
|
||||
return thing->ceilingz;
|
||||
}
|
||||
}
|
||||
|
||||
return thing->Sector->ceilingplane.ZatPoint(thingpos);
|
||||
}
|
||||
|
||||
double RenderPolySprite::PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, double spriteheight, double z2)
|
||||
{
|
||||
int spriteclip = 2; // gl_spriteclip, but use 'always' mode for now
|
||||
|
||||
double z1 = z2 + spriteheight;
|
||||
|
||||
// Tests show that this doesn't look good for many decorations and corpses
|
||||
uint32_t spritetype = (thing->renderflags & RF_SPRITETYPEMASK);
|
||||
if (!(spriteheight > 0 && spriteclip > 0 && spritetype == RF_FACESPRITE))
|
||||
return z2;
|
||||
|
||||
bool clipthing = (thing->player || thing->flags3&MF3_ISMONSTER || thing->IsKindOf(RUNTIME_CLASS(AInventory))) && (thing->flags&MF_ICECORPSE || !(thing->flags&MF_CORPSE));
|
||||
bool smarterclip = !clipthing && spriteclip == 3;
|
||||
if (clipthing || spriteclip > 1)
|
||||
{
|
||||
double diffb = MIN(z2 - GetSpriteFloorZ(thing, thingpos), 0.0);
|
||||
|
||||
// Adjust sprites clipping into ceiling and adjust clipping adjustment for tall graphics
|
||||
if (smarterclip)
|
||||
{
|
||||
// Reduce slightly clipping adjustment of corpses
|
||||
if (thing->flags & MF_CORPSE || spriteheight > fabs(diffb))
|
||||
{
|
||||
double ratio = clamp<double>((fabs(diffb) * (double)gl_sclipfactor / (spriteheight + 1)), 0.5, 1.0);
|
||||
diffb *= ratio;
|
||||
}
|
||||
if (!diffb)
|
||||
{
|
||||
double difft = MAX(z1 - GetSpriteCeilingZ(thing, thingpos), 0.0);
|
||||
if (difft >= (double)gl_sclipthreshold)
|
||||
{
|
||||
// dumb copy of the above.
|
||||
if (!(thing->flags3&MF3_ISMONSTER) || (thing->flags&MF_NOGRAVITY) || (thing->flags&MF_CORPSE) || difft > (double)gl_sclipthreshold)
|
||||
{
|
||||
difft = 0;
|
||||
}
|
||||
}
|
||||
if (spriteheight > fabs(difft))
|
||||
{
|
||||
double ratio = clamp<double>((fabs(difft) * (double)gl_sclipfactor / (spriteheight + 1)), 0.5, 1.0);
|
||||
difft *= ratio;
|
||||
}
|
||||
z2 -= difft;
|
||||
}
|
||||
}
|
||||
if (diffb <= (0 - (double)gl_sclipthreshold)) // such a large displacement can't be correct!
|
||||
{
|
||||
// for living monsters standing on the floor allow a little more.
|
||||
if (!(thing->flags3&MF3_ISMONSTER) || (thing->flags&MF_NOGRAVITY) || (thing->flags&MF_CORPSE) || diffb < (-1.8*(double)gl_sclipthreshold))
|
||||
{
|
||||
diffb = 0;
|
||||
}
|
||||
}
|
||||
|
||||
z2 -= diffb;
|
||||
}
|
||||
return z2;
|
||||
}
|
||||
|
||||
bool RenderPolySprite::IsThingCulled(AActor *thing)
|
||||
|
@ -180,7 +295,7 @@ bool RenderPolySprite::IsThingCulled(AActor *thing)
|
|||
|
||||
// check renderrequired vs ~r_rendercaps, if anything matches we don't support that feature,
|
||||
// check renderhidden vs r_rendercaps, if anything matches we do support that feature and should hide it.
|
||||
if (!r_debug_disable_vis_filter && (!!(thing->RenderRequired & ~r_renderercaps)) ||
|
||||
if ((!r_debug_disable_vis_filter && !!(thing->RenderRequired & ~r_renderercaps)) ||
|
||||
(!!(thing->RenderHidden & r_renderercaps)))
|
||||
return true;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Handling drawing a sprite
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -27,12 +27,40 @@
|
|||
class RenderPolySprite
|
||||
{
|
||||
public:
|
||||
void Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue, float t1, float t2);
|
||||
void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t stencilValue, float t1, float t2);
|
||||
|
||||
static bool GetLine(AActor *thing, DVector2 &left, DVector2 &right);
|
||||
static bool IsThingCulled(AActor *thing);
|
||||
static FTexture *GetSpriteTexture(AActor *thing, /*out*/ bool &flipX);
|
||||
|
||||
private:
|
||||
//visstyle_t GetSpriteVisStyle(AActor *thing, double z);
|
||||
static double PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, double spriteheight, double z);
|
||||
static double GetSpriteFloorZ(AActor *thing, const DVector2 &thingpos);
|
||||
static double GetSpriteCeilingZ(AActor *thing, const DVector2 &thingpos);
|
||||
};
|
||||
|
||||
class PolyTranslucentThing : public PolyTranslucentObject
|
||||
{
|
||||
public:
|
||||
PolyTranslucentThing(AActor *thing, subsector_t *sub, uint32_t subsectorDepth, double dist, float t1, float t2, uint32_t stencilValue) : PolyTranslucentObject(subsectorDepth, dist), thing(thing), sub(sub), SpriteLeft(t1), SpriteRight(t2), StencilValue(stencilValue) { }
|
||||
|
||||
void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &portalPlane) override
|
||||
{
|
||||
if ((thing->renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE)
|
||||
{
|
||||
RenderPolyWallSprite wallspr;
|
||||
wallspr.Render(thread, worldToClip, portalPlane, thing, sub, StencilValue + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderPolySprite spr;
|
||||
spr.Render(thread, worldToClip, portalPlane, thing, sub, StencilValue + 1, SpriteLeft, SpriteRight);
|
||||
}
|
||||
}
|
||||
|
||||
AActor *thing = nullptr;
|
||||
subsector_t *sub = nullptr;
|
||||
float SpriteLeft = 0.0f;
|
||||
float SpriteRight = 1.0f;
|
||||
uint32_t StencilValue = 0;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Handling drawing a wall
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -33,11 +33,13 @@
|
|||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "r_sky.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
#include "g_levellocals.h"
|
||||
|
||||
EXTERN_CVAR(Bool, r_drawmirrors)
|
||||
EXTERN_CVAR(Bool, r_fogboundary)
|
||||
|
||||
bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals, line_t *lastPortalLine)
|
||||
bool RenderPolyWall::RenderLine(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals, line_t *lastPortalLine)
|
||||
{
|
||||
double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1);
|
||||
double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1);
|
||||
|
@ -88,6 +90,7 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const PolyClipPlan
|
|||
wall.LineSeg = line;
|
||||
wall.Line = line->linedef;
|
||||
wall.Side = line->sidedef;
|
||||
wall.LineSegLine = line->linedef;
|
||||
wall.Colormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::walltop]);
|
||||
wall.Masked = false;
|
||||
wall.SubsectorDepth = subsectorDepth;
|
||||
|
@ -100,15 +103,16 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const PolyClipPlan
|
|||
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), frontceilz1, frontfloorz1, frontceilz2, frontfloorz2);
|
||||
wall.TopTexZ = topTexZ;
|
||||
wall.BottomTexZ = bottomTexZ;
|
||||
wall.Texpart = side_t::mid;
|
||||
wall.Wallpart = side_t::mid;
|
||||
wall.Texture = GetTexture(wall.Line, wall.Side, side_t::mid);
|
||||
wall.Polyportal = polyportal;
|
||||
wall.Render(worldToClip, clipPlane, cull);
|
||||
wall.Render(thread, worldToClip, clipPlane);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sector_t *backsector = (line->backsector != line->frontsector) ? line->backsector : line->frontsector;
|
||||
sector_t *backsector = line->backsector;
|
||||
|
||||
double backceilz1 = backsector->ceilingplane.ZatPoint(line->v1);
|
||||
double backfloorz1 = backsector->floorplane.ZatPoint(line->v1);
|
||||
|
@ -136,8 +140,9 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const PolyClipPlan
|
|||
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), topceilz1, topfloorz1, topceilz2, topfloorz2);
|
||||
wall.TopTexZ = topTexZ;
|
||||
wall.BottomTexZ = MIN(MIN(backceilz1, frontceilz1), MIN(backceilz2, frontceilz2));
|
||||
wall.Texpart = side_t::top;
|
||||
wall.Render(worldToClip, clipPlane, cull);
|
||||
wall.Wallpart = side_t::top;
|
||||
wall.Texture = GetTexture(wall.Line, wall.Side, side_t::top);
|
||||
wall.Render(thread, worldToClip, clipPlane);
|
||||
}
|
||||
|
||||
if ((bottomfloorz1 < bottomceilz1 || bottomfloorz2 < bottomceilz2) && line->sidedef && !bothSkyFloor)
|
||||
|
@ -147,8 +152,9 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const PolyClipPlan
|
|||
wall.BottomTexZ = bottomTexZ;
|
||||
wall.UnpeggedCeil1 = topceilz1;
|
||||
wall.UnpeggedCeil2 = topceilz2;
|
||||
wall.Texpart = side_t::bottom;
|
||||
wall.Render(worldToClip, clipPlane, cull);
|
||||
wall.Wallpart = side_t::bottom;
|
||||
wall.Texture = GetTexture(wall.Line, wall.Side, side_t::bottom);
|
||||
wall.Render(thread, worldToClip, clipPlane);
|
||||
}
|
||||
|
||||
if (line->sidedef)
|
||||
|
@ -156,47 +162,86 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const PolyClipPlan
|
|||
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), middleceilz1, middlefloorz1, middleceilz2, middlefloorz2);
|
||||
wall.TopTexZ = MAX(middleceilz1, middleceilz2);
|
||||
wall.BottomTexZ = MIN(middlefloorz1, middlefloorz2);
|
||||
wall.Texpart = side_t::mid;
|
||||
wall.Wallpart = side_t::mid;
|
||||
wall.Texture = GetTexture(wall.Line, wall.Side, side_t::mid);
|
||||
wall.Masked = true;
|
||||
wall.Additive = !!(wall.Line->flags & ML_ADDTRANS);
|
||||
wall.Alpha = wall.Line->alpha;
|
||||
wall.FogBoundary = IsFogBoundary(frontsector, backsector);
|
||||
|
||||
FTexture *midtex = TexMan(line->sidedef->GetTexture(side_t::mid), true);
|
||||
if (midtex && midtex->UseType != FTexture::TEX_Null)
|
||||
translucentWallsOutput.push_back(PolyRenderer::Instance()->FrameMemory.NewObject<PolyTranslucentObject>(wall));
|
||||
if ((midtex && midtex->UseType != FTexture::TEX_Null) || wall.FogBoundary)
|
||||
translucentWallsOutput.push_back(thread->FrameMemory->NewObject<PolyTranslucentWall>(wall));
|
||||
|
||||
if (polyportal)
|
||||
{
|
||||
wall.Polyportal = polyportal;
|
||||
wall.Render(worldToClip, clipPlane, cull);
|
||||
wall.Render(thread, worldToClip, clipPlane);
|
||||
}
|
||||
}
|
||||
}
|
||||
return polyportal != nullptr;
|
||||
}
|
||||
|
||||
void RenderPolyWall::Render3DFloorLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput)
|
||||
bool RenderPolyWall::IsFogBoundary(sector_t *front, sector_t *back)
|
||||
{
|
||||
return r_fogboundary && PolyCameraLight::Instance()->FixedColormap() == nullptr && front->Colormap.FadeColor &&
|
||||
front->Colormap.FadeColor != back->Colormap.FadeColor &&
|
||||
(front->GetTexture(sector_t::ceiling) != skyflatnum || back->GetTexture(sector_t::ceiling) != skyflatnum);
|
||||
}
|
||||
|
||||
void RenderPolyWall::Render3DFloorLine(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput)
|
||||
{
|
||||
if (!(fakeFloor->flags & FF_EXISTS)) return;
|
||||
if (!(fakeFloor->flags & FF_RENDERPLANES)) return;
|
||||
if (fakeFloor->flags & FF_SWIMMABLE) return;
|
||||
if (!fakeFloor->model) return;
|
||||
if (fakeFloor->alpha == 0) return;
|
||||
|
||||
double frontceilz1 = fakeFloor->top.plane->ZatPoint(line->v1);
|
||||
double frontfloorz1 = fakeFloor->bottom.plane->ZatPoint(line->v1);
|
||||
double frontceilz2 = fakeFloor->top.plane->ZatPoint(line->v2);
|
||||
double frontfloorz2 = fakeFloor->bottom.plane->ZatPoint(line->v2);
|
||||
double topTexZ = frontsector->GetPlaneTexZ(sector_t::ceiling);
|
||||
double bottomTexZ = frontsector->GetPlaneTexZ(sector_t::floor);
|
||||
double topTexZ = fakeFloor->model->GetPlaneTexZ(sector_t::ceiling);
|
||||
double bottomTexZ = fakeFloor->model->GetPlaneTexZ(sector_t::floor);
|
||||
|
||||
if (frontceilz1 <= frontfloorz1 || frontceilz2 <= frontfloorz2)
|
||||
return;
|
||||
|
||||
RenderPolyWall wall;
|
||||
wall.LineSeg = line;
|
||||
wall.LineSegLine = line->linedef;
|
||||
wall.Line = fakeFloor->master;
|
||||
wall.Side = fakeFloor->master->sidedef[0];
|
||||
wall.Colormap = GetColorTable(frontsector->Colormap, frontsector->SpecialColors[sector_t::walltop]);
|
||||
wall.Masked = false;
|
||||
wall.Additive = !!(fakeFloor->flags & FF_ADDITIVETRANS);
|
||||
if (!wall.Additive && fakeFloor->alpha == 255)
|
||||
{
|
||||
wall.Masked = false;
|
||||
wall.Alpha = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
wall.Masked = true;
|
||||
wall.Alpha = fakeFloor->alpha / 255.0;
|
||||
}
|
||||
wall.SubsectorDepth = subsectorDepth;
|
||||
wall.StencilValue = stencilValue;
|
||||
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), frontceilz1, frontfloorz1, frontceilz2, frontfloorz2);
|
||||
wall.TopTexZ = topTexZ;
|
||||
wall.BottomTexZ = bottomTexZ;
|
||||
wall.UnpeggedCeil1 = frontceilz1;
|
||||
wall.UnpeggedCeil2 = frontceilz2;
|
||||
wall.Texpart = side_t::mid;
|
||||
wall.Render(worldToClip, clipPlane, cull);
|
||||
wall.Wallpart = side_t::mid;
|
||||
if (fakeFloor->flags & FF_UPPERTEXTURE)
|
||||
wall.Texture = GetTexture(line->linedef, line->sidedef, side_t::top);
|
||||
else if (fakeFloor->flags & FF_LOWERTEXTURE)
|
||||
wall.Texture = GetTexture(line->linedef, line->sidedef, side_t::bottom);
|
||||
else
|
||||
wall.Texture = GetTexture(wall.Line, wall.Side, side_t::mid);
|
||||
|
||||
if (!wall.Masked)
|
||||
wall.Render(thread, worldToClip, clipPlane);
|
||||
else
|
||||
translucentWallsOutput.push_back(thread->FrameMemory->NewObject<PolyTranslucentWall>(wall));
|
||||
}
|
||||
|
||||
void RenderPolyWall::SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2)
|
||||
|
@ -209,14 +254,13 @@ void RenderPolyWall::SetCoords(const DVector2 &v1, const DVector2 &v2, double ce
|
|||
this->floor2 = floor2;
|
||||
}
|
||||
|
||||
void RenderPolyWall::Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull)
|
||||
void RenderPolyWall::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane)
|
||||
{
|
||||
bool foggy = false;
|
||||
FTexture *tex = GetTexture();
|
||||
if (!tex && !Polyportal)
|
||||
if (!Texture && !Polyportal && !FogBoundary)
|
||||
return;
|
||||
|
||||
TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(4);
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
|
||||
vertices[0].x = (float)v1.X;
|
||||
vertices[0].y = (float)v1.Y;
|
||||
|
@ -238,11 +282,11 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const PolyClipPlane &c
|
|||
vertices[3].z = (float)floor1;
|
||||
vertices[3].w = 1.0f;
|
||||
|
||||
if (tex)
|
||||
if (Texture)
|
||||
{
|
||||
PolyWallTextureCoordsU texcoordsU(tex, LineSeg, Line, Side, Texpart);
|
||||
PolyWallTextureCoordsV texcoordsVLeft(tex, Line, Side, Texpart, ceil1, floor1, UnpeggedCeil1, TopTexZ, BottomTexZ);
|
||||
PolyWallTextureCoordsV texcoordsVRght(tex, Line, Side, Texpart, ceil2, floor2, UnpeggedCeil2, TopTexZ, BottomTexZ);
|
||||
PolyWallTextureCoordsU texcoordsU(Texture, LineSeg, LineSegLine, Side, Wallpart);
|
||||
PolyWallTextureCoordsV texcoordsVLeft(Texture, Line, Side, Wallpart, ceil1, floor1, UnpeggedCeil1, TopTexZ, BottomTexZ);
|
||||
PolyWallTextureCoordsV texcoordsVRght(Texture, Line, Side, Wallpart, ceil2, floor2, UnpeggedCeil2, TopTexZ, BottomTexZ);
|
||||
vertices[0].u = (float)texcoordsU.u1;
|
||||
vertices[0].v = (float)texcoordsVLeft.v1;
|
||||
vertices[1].u = (float)texcoordsU.u2;
|
||||
|
@ -264,47 +308,115 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const PolyClipPlane &c
|
|||
// Masked walls clamp to the 0-1 range (no texture repeat)
|
||||
if (Masked)
|
||||
{
|
||||
ClampHeight(vertices[0], vertices[3]);
|
||||
ClampHeight(vertices[1], vertices[2]);
|
||||
bool wrap = (Line->flags & ML_WRAP_MIDTEX) || (Side->Flags & WALLF_WRAP_MIDTEX);
|
||||
if (!wrap)
|
||||
{
|
||||
ClampHeight(vertices[0], vertices[3]);
|
||||
ClampHeight(vertices[1], vertices[2]);
|
||||
}
|
||||
}
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(GetColorTable(Line->frontsector->Colormap, Line->frontsector->SpecialColors[sector_t::walltop]), GetLightLevel(), PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
|
||||
args.SetSubsectorDepth(SubsectorDepth);
|
||||
args.SetTransform(&worldToClip);
|
||||
args.SetFaceCullCCW(true);
|
||||
args.SetStencilTestValue(StencilValue);
|
||||
args.SetWriteStencil(true, StencilValue + 1);
|
||||
if (tex && !Polyportal)
|
||||
args.SetTexture(tex);
|
||||
args.SetClipPlane(clipPlane);
|
||||
if (Texture && !Polyportal)
|
||||
args.SetTexture(Texture);
|
||||
args.SetClipPlane(0, clipPlane);
|
||||
|
||||
if (FogBoundary)
|
||||
{
|
||||
args.SetStyle(TriBlendMode::FogBoundary);
|
||||
args.SetColor(0xffffffff, 254);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
args.SetWriteStencil(false);
|
||||
args.DrawArray(thread, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
if (!Texture)
|
||||
return;
|
||||
}
|
||||
|
||||
if (Polyportal)
|
||||
{
|
||||
args.SetWriteStencil(true, Polyportal->StencilValue);
|
||||
args.SetWriteColor(false);
|
||||
args.SetWriteSubsectorDepth(false);
|
||||
args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
|
||||
Polyportal->Shape.push_back({ vertices, 4, true, SubsectorDepth });
|
||||
args.SetWriteDepth(false);
|
||||
args.DrawArray(thread, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
Polyportal->Shape.push_back({ vertices, 4, true });
|
||||
}
|
||||
else if (!Masked)
|
||||
{
|
||||
args.SetStyle(TriBlendMode::TextureOpaque);
|
||||
args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
|
||||
DrawStripes(thread, args, vertices);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool addtrans = !!(Line->flags & ML_ADDTRANS);
|
||||
double srcalpha = MIN(Line->alpha, 1.0);
|
||||
double destalpha = addtrans ? 1.0 : 1.0 - srcalpha;
|
||||
double srcalpha = MIN(Alpha, 1.0);
|
||||
double destalpha = Additive ? 1.0 : 1.0 - srcalpha;
|
||||
args.SetStyle(TriBlendMode::TextureAdd, srcalpha, destalpha);
|
||||
args.SetSubsectorDepthTest(true);
|
||||
args.SetWriteSubsectorDepth(true);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
args.SetWriteStencil(false);
|
||||
args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
|
||||
DrawStripes(thread, args, vertices);
|
||||
}
|
||||
|
||||
RenderPolyDecal::RenderWallDecals(worldToClip, clipPlane, LineSeg, SubsectorDepth, StencilValue);
|
||||
RenderPolyDecal::RenderWallDecals(thread, worldToClip, clipPlane, LineSeg, StencilValue);
|
||||
}
|
||||
|
||||
void RenderPolyWall::DrawStripes(PolyRenderThread *thread, PolyDrawArgs &args, TriVertex *vertices)
|
||||
{
|
||||
const auto &lightlist = Line->frontsector->e->XFloor.lightlist;
|
||||
if (lightlist.Size() > 0)
|
||||
{
|
||||
PolyClipPlane topPlane;
|
||||
|
||||
for (unsigned int i = 0; i < lightlist.Size(); i++)
|
||||
{
|
||||
lightlist_t *lit = &lightlist[i];
|
||||
|
||||
DVector3 normal = lit->plane.Normal();
|
||||
double d = lit->plane.fD();
|
||||
if (normal.Z < 0.0)
|
||||
{
|
||||
normal = -normal;
|
||||
d = -d;
|
||||
}
|
||||
|
||||
PolyClipPlane bottomPlane = { (float)normal.X, (float)normal.Y, (float)normal.Z, (float)d };
|
||||
|
||||
args.SetClipPlane(1, topPlane);
|
||||
args.SetClipPlane(2, bottomPlane);
|
||||
args.DrawArray(thread, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
|
||||
FDynamicColormap *basecolormap = GetColorTable(lit->extra_colormap, Line->frontsector->SpecialColors[sector_t::walltop]);
|
||||
|
||||
bool foggy = false;
|
||||
int lightlevel;
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
if (cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
|
||||
{
|
||||
lightlevel = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
lightlevel = clamp(Side->GetLightLevel(foggy, *lit->p_lightlevel) + actualextralight, 0, 255);
|
||||
}
|
||||
args.SetLight(basecolormap, lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
|
||||
|
||||
topPlane = { (float)-normal.X, (float)-normal.Y, (float)-normal.Z, (float)-d };
|
||||
}
|
||||
|
||||
args.SetClipPlane(1, topPlane);
|
||||
args.SetClipPlane(2, PolyClipPlane());
|
||||
args.DrawArray(thread, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
else
|
||||
{
|
||||
args.DrawArray(thread, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyWall::ClampHeight(TriVertex &v1, TriVertex &v2)
|
||||
|
@ -327,27 +439,27 @@ void RenderPolyWall::ClampHeight(TriVertex &v1, TriVertex &v2)
|
|||
v2.v = texv1 * inv_t2 + texv2 * t2;
|
||||
}
|
||||
|
||||
FTexture *RenderPolyWall::GetTexture()
|
||||
FTexture *RenderPolyWall::GetTexture(const line_t *line, const side_t *side, side_t::ETexpart texpart)
|
||||
{
|
||||
FTexture *tex = TexMan(Side->GetTexture(Texpart), true);
|
||||
FTexture *tex = TexMan(side->GetTexture(texpart), true);
|
||||
if (tex == nullptr || tex->UseType == FTexture::TEX_Null)
|
||||
{
|
||||
// Mapping error. Doom floodfills this with a plane.
|
||||
// This code doesn't do that, but at least it uses the "right" texture..
|
||||
|
||||
if (Line && Line->backsector && Line->sidedef[0] == Side)
|
||||
if (line && line->backsector && line->sidedef[0] == side)
|
||||
{
|
||||
if (Texpart == side_t::top)
|
||||
tex = TexMan(Line->backsector->GetTexture(sector_t::ceiling), true);
|
||||
else if (Texpart == side_t::bottom)
|
||||
tex = TexMan(Line->backsector->GetTexture(sector_t::floor), true);
|
||||
if (texpart == side_t::top)
|
||||
tex = TexMan(line->backsector->GetTexture(sector_t::ceiling), true);
|
||||
else if (texpart == side_t::bottom)
|
||||
tex = TexMan(line->backsector->GetTexture(sector_t::floor), true);
|
||||
}
|
||||
if (Line && Line->backsector && Line->sidedef[1] == Side)
|
||||
if (line && line->backsector && line->sidedef[1] == side)
|
||||
{
|
||||
if (Texpart == side_t::top)
|
||||
tex = TexMan(Line->frontsector->GetTexture(sector_t::ceiling), true);
|
||||
else if (Texpart == side_t::bottom)
|
||||
tex = TexMan(Line->frontsector->GetTexture(sector_t::floor), true);
|
||||
if (texpart == side_t::top)
|
||||
tex = TexMan(line->frontsector->GetTexture(sector_t::ceiling), true);
|
||||
else if (texpart == side_t::bottom)
|
||||
tex = TexMan(line->frontsector->GetTexture(sector_t::floor), true);
|
||||
}
|
||||
|
||||
if (tex == nullptr || tex->UseType == FTexture::TEX_Null)
|
||||
|
@ -373,59 +485,62 @@ int RenderPolyWall::GetLightLevel()
|
|||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyWallTextureCoordsU::PolyWallTextureCoordsU(FTexture *tex, const seg_t *lineseg, const line_t *line, const side_t *side, side_t::ETexpart texpart)
|
||||
PolyWallTextureCoordsU::PolyWallTextureCoordsU(FTexture *tex, const seg_t *lineseg, const line_t *line, const side_t *side, side_t::ETexpart wallpart)
|
||||
{
|
||||
// Calculate the U texture coordinate for the line
|
||||
double lineu1 = side->GetTextureXOffset(wallpart);
|
||||
double lineu2 = side->GetTextureXOffset(wallpart) + line->sidedef[0]->TexelLength * side->GetTextureXScale(wallpart);
|
||||
lineu1 *= tex->Scale.X / tex->GetWidth();
|
||||
lineu2 *= tex->Scale.X / tex->GetWidth();
|
||||
|
||||
// Calculate where we are on the lineseg
|
||||
double t1, t2;
|
||||
double deltaX = line->v2->fX() - line->v1->fX();
|
||||
double deltaY = line->v2->fY() - line->v1->fY();
|
||||
if (fabs(deltaX) > fabs(deltaY))
|
||||
if (fabs(line->delta.X) > fabs(line->delta.Y))
|
||||
{
|
||||
t1 = (lineseg->v1->fX() - line->v1->fX()) / deltaX;
|
||||
t2 = (lineseg->v2->fX() - line->v1->fX()) / deltaX;
|
||||
t1 = (lineseg->v1->fX() - line->v1->fX()) / line->delta.X;
|
||||
t2 = (lineseg->v2->fX() - line->v1->fX()) / line->delta.X;
|
||||
}
|
||||
else
|
||||
{
|
||||
t1 = (lineseg->v1->fY() - line->v1->fY()) / deltaY;
|
||||
t2 = (lineseg->v2->fY() - line->v1->fY()) / deltaY;
|
||||
t1 = (lineseg->v1->fY() - line->v1->fY()) / line->delta.Y;
|
||||
t2 = (lineseg->v2->fY() - line->v1->fY()) / line->delta.Y;
|
||||
}
|
||||
|
||||
int texWidth = tex->GetWidth();
|
||||
double uscale = side->GetTextureXScale(texpart) * tex->Scale.X;
|
||||
u1 = t1 * side->TexelLength + side->GetTextureXOffset(texpart);
|
||||
u2 = t2 * side->TexelLength + side->GetTextureXOffset(texpart);
|
||||
u1 *= uscale;
|
||||
u2 *= uscale;
|
||||
u1 /= texWidth;
|
||||
u2 /= texWidth;
|
||||
// Check if lineseg is the backside of the line
|
||||
if (t2 < t1)
|
||||
{
|
||||
std::swap(lineu1, lineu2);
|
||||
}
|
||||
|
||||
// Calculate texture coordinates for the lineseg
|
||||
u1 = (1.0 - t1) * lineu1 + t1 * lineu2;
|
||||
u2 = (1.0 - t2) * lineu1 + t2 * lineu2;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyWallTextureCoordsV::PolyWallTextureCoordsV(FTexture *tex, const line_t *line, const side_t *side, side_t::ETexpart texpart, double topz, double bottomz, double unpeggedceil, double topTexZ, double bottomTexZ)
|
||||
PolyWallTextureCoordsV::PolyWallTextureCoordsV(FTexture *tex, const line_t *line, const side_t *side, side_t::ETexpart wallpart, double topz, double bottomz, double unpeggedceil, double topTexZ, double bottomTexZ)
|
||||
{
|
||||
double vscale = side->GetTextureYScale(texpart) * tex->Scale.Y;
|
||||
|
||||
double yoffset = side->GetTextureYOffset(texpart);
|
||||
double yoffset = side->GetTextureYOffset(wallpart);
|
||||
if (tex->bWorldPanning)
|
||||
yoffset *= vscale;
|
||||
yoffset *= side->GetTextureYScale(wallpart) * tex->Scale.Y;
|
||||
|
||||
switch (texpart)
|
||||
switch (wallpart)
|
||||
{
|
||||
default:
|
||||
case side_t::mid:
|
||||
CalcVMidPart(tex, line, side, topTexZ, bottomTexZ, vscale, yoffset);
|
||||
CalcVMidPart(tex, line, side, topTexZ, bottomTexZ, yoffset);
|
||||
break;
|
||||
case side_t::top:
|
||||
CalcVTopPart(tex, line, side, topTexZ, bottomTexZ, vscale, yoffset);
|
||||
CalcVTopPart(tex, line, side, topTexZ, bottomTexZ, yoffset);
|
||||
break;
|
||||
case side_t::bottom:
|
||||
CalcVBottomPart(tex, line, side, topTexZ, bottomTexZ, unpeggedceil, vscale, yoffset);
|
||||
CalcVBottomPart(tex, line, side, topTexZ, bottomTexZ, unpeggedceil, yoffset);
|
||||
break;
|
||||
}
|
||||
|
||||
int texHeight = tex->GetHeight();
|
||||
v1 /= texHeight;
|
||||
v2 /= texHeight;
|
||||
v1 *= tex->Scale.Y / tex->GetHeight();
|
||||
v2 *= tex->Scale.Y / tex->GetHeight();
|
||||
|
||||
double texZHeight = (bottomTexZ - topTexZ);
|
||||
if (texZHeight > 0.0f || texZHeight < -0.0f)
|
||||
|
@ -439,60 +554,53 @@ PolyWallTextureCoordsV::PolyWallTextureCoordsV(FTexture *tex, const line_t *line
|
|||
}
|
||||
}
|
||||
|
||||
void PolyWallTextureCoordsV::CalcVTopPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double vscale, double yoffset)
|
||||
void PolyWallTextureCoordsV::CalcVTopPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset)
|
||||
{
|
||||
bool pegged = (line->flags & ML_DONTPEGTOP) == 0;
|
||||
if (pegged) // bottom to top
|
||||
{
|
||||
int texHeight = tex->GetHeight();
|
||||
v1 = -yoffset;
|
||||
v2 = v1 + (topz - bottomz);
|
||||
v1 *= vscale;
|
||||
v2 *= vscale;
|
||||
double texHeight = tex->GetHeight() / tex->Scale.Y;
|
||||
v1 = (topz - bottomz) * side->GetTextureYScale(side_t::top) - yoffset;
|
||||
v2 = -yoffset;
|
||||
v1 = texHeight - v1;
|
||||
v2 = texHeight - v2;
|
||||
std::swap(v1, v2);
|
||||
}
|
||||
else // top to bottom
|
||||
{
|
||||
v1 = yoffset;
|
||||
v2 = v1 + (topz - bottomz);
|
||||
v1 *= vscale;
|
||||
v2 *= vscale;
|
||||
v2 = (topz - bottomz) * side->GetTextureYScale(side_t::top) + yoffset;
|
||||
}
|
||||
}
|
||||
|
||||
void PolyWallTextureCoordsV::CalcVMidPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double vscale, double yoffset)
|
||||
{
|
||||
bool pegged = (line->flags & ML_DONTPEGBOTTOM) == 0;
|
||||
if (pegged) // top to bottom
|
||||
{
|
||||
v1 = yoffset * vscale;
|
||||
v2 = (yoffset + (topz - bottomz)) * vscale;
|
||||
}
|
||||
else // bottom to top
|
||||
{
|
||||
int texHeight = tex->GetHeight();
|
||||
v1 = texHeight - (-yoffset + (topz - bottomz)) * vscale;
|
||||
v2 = texHeight + yoffset * vscale;
|
||||
}
|
||||
}
|
||||
|
||||
void PolyWallTextureCoordsV::CalcVBottomPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double unpeggedceil, double vscale, double yoffset)
|
||||
void PolyWallTextureCoordsV::CalcVMidPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset)
|
||||
{
|
||||
bool pegged = (line->flags & ML_DONTPEGBOTTOM) == 0;
|
||||
if (pegged) // top to bottom
|
||||
{
|
||||
v1 = yoffset;
|
||||
v2 = v1 + (topz - bottomz);
|
||||
v1 *= vscale;
|
||||
v2 *= vscale;
|
||||
v2 = (topz - bottomz) * side->GetTextureYScale(side_t::mid) + yoffset;
|
||||
}
|
||||
else // bottom to top
|
||||
{
|
||||
double texHeight = tex->GetHeight() / tex->Scale.Y;
|
||||
v1 = yoffset - (topz - bottomz) * side->GetTextureYScale(side_t::mid);
|
||||
v2 = yoffset;
|
||||
v1 = texHeight + v1;
|
||||
v2 = texHeight + v2;
|
||||
}
|
||||
}
|
||||
|
||||
void PolyWallTextureCoordsV::CalcVBottomPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double unpeggedceil, double yoffset)
|
||||
{
|
||||
bool pegged = (line->flags & ML_DONTPEGBOTTOM) == 0;
|
||||
if (pegged) // top to bottom
|
||||
{
|
||||
v1 = yoffset;
|
||||
v2 = yoffset + (topz - bottomz) * side->GetTextureYScale(side_t::bottom);
|
||||
}
|
||||
else
|
||||
{
|
||||
v1 = yoffset + (unpeggedceil - topz);
|
||||
v2 = v1 + (topz - bottomz);
|
||||
v1 *= vscale;
|
||||
v2 *= vscale;
|
||||
v1 = yoffset + (unpeggedceil - topz) * side->GetTextureYScale(side_t::bottom);
|
||||
v2 = yoffset + (unpeggedceil - bottomz) * side->GetTextureYScale(side_t::bottom);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Handling drawing a wall
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -31,11 +31,11 @@ class PolyCull;
|
|||
class RenderPolyWall
|
||||
{
|
||||
public:
|
||||
static bool RenderLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals, line_t *lastPortalLine);
|
||||
static void Render3DFloorLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput);
|
||||
static bool RenderLine(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals, line_t *lastPortalLine);
|
||||
static void Render3DFloorLine(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput);
|
||||
|
||||
void SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2);
|
||||
void Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull);
|
||||
void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane);
|
||||
|
||||
DVector2 v1;
|
||||
DVector2 v2;
|
||||
|
@ -45,29 +45,37 @@ public:
|
|||
double floor2 = 0.0;
|
||||
|
||||
const seg_t *LineSeg = nullptr;
|
||||
const line_t *LineSegLine = nullptr;
|
||||
const line_t *Line = nullptr;
|
||||
const side_t *Side = nullptr;
|
||||
side_t::ETexpart Texpart = side_t::mid;
|
||||
FTexture *Texture = nullptr;
|
||||
side_t::ETexpart Wallpart = side_t::mid;
|
||||
double TopTexZ = 0.0;
|
||||
double BottomTexZ = 0.0;
|
||||
double UnpeggedCeil1 = 0.0;
|
||||
double UnpeggedCeil2 = 0.0;
|
||||
FSWColormap *Colormap = nullptr;
|
||||
bool Masked = false;
|
||||
bool Additive = false;
|
||||
double Alpha = 1.0;
|
||||
bool FogBoundary = false;
|
||||
uint32_t SubsectorDepth = 0;
|
||||
uint32_t StencilValue = 0;
|
||||
PolyDrawLinePortal *Polyportal = nullptr;
|
||||
|
||||
private:
|
||||
void ClampHeight(TriVertex &v1, TriVertex &v2);
|
||||
FTexture *GetTexture();
|
||||
int GetLightLevel();
|
||||
void DrawStripes(PolyRenderThread *thread, PolyDrawArgs &args, TriVertex *vertices);
|
||||
|
||||
static bool IsFogBoundary(sector_t *front, sector_t *back);
|
||||
static FTexture *GetTexture(const line_t *Line, const side_t *Side, side_t::ETexpart texpart);
|
||||
};
|
||||
|
||||
class PolyWallTextureCoordsU
|
||||
{
|
||||
public:
|
||||
PolyWallTextureCoordsU(FTexture *tex, const seg_t *lineseg, const line_t *line, const side_t *side, side_t::ETexpart texpart);
|
||||
PolyWallTextureCoordsU(FTexture *tex, const seg_t *lineseg, const line_t *linesegline, const side_t *side, side_t::ETexpart wallpart);
|
||||
|
||||
double u1, u2;
|
||||
};
|
||||
|
@ -75,12 +83,25 @@ public:
|
|||
class PolyWallTextureCoordsV
|
||||
{
|
||||
public:
|
||||
PolyWallTextureCoordsV(FTexture *tex, const line_t *line, const side_t *side, side_t::ETexpart texpart, double topz, double bottomz, double unpeggedceil, double topTexZ, double bottomTexZ);
|
||||
PolyWallTextureCoordsV(FTexture *tex, const line_t *line, const side_t *side, side_t::ETexpart wallpart, double topz, double bottomz, double unpeggedceil, double topTexZ, double bottomTexZ);
|
||||
|
||||
double v1, v2;
|
||||
|
||||
private:
|
||||
void CalcVTopPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double vscale, double yoffset);
|
||||
void CalcVMidPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double vscale, double yoffset);
|
||||
void CalcVBottomPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double unpeggedceil, double vscale, double yoffset);
|
||||
void CalcVTopPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset);
|
||||
void CalcVMidPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset);
|
||||
void CalcVBottomPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double unpeggedceil, double yoffset);
|
||||
};
|
||||
|
||||
class PolyTranslucentWall : public PolyTranslucentObject
|
||||
{
|
||||
public:
|
||||
PolyTranslucentWall(RenderPolyWall wall) : PolyTranslucentObject(wall.SubsectorDepth, 1e6), wall(wall) { }
|
||||
|
||||
void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &portalPlane) override
|
||||
{
|
||||
wall.Render(thread, worldToClip, portalPlane);
|
||||
}
|
||||
|
||||
RenderPolyWall wall;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Handling drawing a sprite
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -28,8 +28,9 @@
|
|||
#include "poly_wallsprite.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
|
||||
void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue)
|
||||
void RenderPolyWallSprite::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t stencilValue)
|
||||
{
|
||||
if (RenderPolySprite::IsThingCulled(thing))
|
||||
return;
|
||||
|
@ -69,7 +70,7 @@ void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, const PolyClipPl
|
|||
|
||||
DVector2 points[2] = { left, right };
|
||||
|
||||
TriVertex *vertices = PolyRenderer::Instance()->FrameMemory.AllocMemory<TriVertex>(4);
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : viewpoint.extralight << 4;
|
||||
|
@ -105,10 +106,10 @@ void RenderPolyWallSprite::Render(const TriMatrix &worldToClip, const PolyClipPl
|
|||
args.SetFaceCullCCW(true);
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetTexture(tex);
|
||||
args.SetClipPlane(clipPlane);
|
||||
args.SetSubsectorDepthTest(true);
|
||||
args.SetWriteSubsectorDepth(false);
|
||||
args.SetClipPlane(0, clipPlane);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(false);
|
||||
args.SetWriteStencil(false);
|
||||
args.SetStyle(TriBlendMode::TextureMasked);
|
||||
args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
|
||||
args.DrawArray(thread, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** Handling drawing a wall sprite
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
|
@ -27,5 +27,5 @@
|
|||
class RenderPolyWallSprite
|
||||
{
|
||||
public:
|
||||
void Render(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue);
|
||||
void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t stencilValue);
|
||||
};
|
||||
|
|
|
@ -149,9 +149,16 @@ bool I_SetCursor(FTexture *);
|
|||
|
||||
struct findstate_t
|
||||
{
|
||||
private:
|
||||
int count;
|
||||
struct dirent **namelist;
|
||||
int current;
|
||||
|
||||
friend void *I_FindFirst(const char *filespec, findstate_t *fileinfo);
|
||||
friend int I_FindNext(void *handle, findstate_t *fileinfo);
|
||||
friend const char *I_FindName(findstate_t *fileinfo);
|
||||
friend int I_FindAttr(findstate_t *fileinfo);
|
||||
friend int I_FindClose(void *handle);
|
||||
};
|
||||
|
||||
void *I_FindFirst (const char *filespec, findstate_t *fileinfo);
|
||||
|
@ -159,7 +166,10 @@ int I_FindNext (void *handle, findstate_t *fileinfo);
|
|||
int I_FindClose (void *handle);
|
||||
int I_FindAttr (findstate_t *fileinfo);
|
||||
|
||||
#define I_FindName(a) ((a)->namelist[(a)->current]->d_name)
|
||||
inline const char *I_FindName(findstate_t *fileinfo)
|
||||
{
|
||||
return (fileinfo->namelist[fileinfo->current]->d_name);
|
||||
}
|
||||
|
||||
#define FA_RDONLY 1
|
||||
#define FA_HIDDEN 2
|
||||
|
|
|
@ -395,11 +395,11 @@ static NSString* GetArchitectureString()
|
|||
#endif
|
||||
}
|
||||
|
||||
static void RestartWithParameters(const char* iwadPath, NSString* parameters)
|
||||
static void RestartWithParameters(const WadStuff& wad, NSString* parameters)
|
||||
{
|
||||
assert(nil != parameters);
|
||||
|
||||
defaultiwad = ExtractFileBase(iwadPath);
|
||||
defaultiwad = wad.Name;
|
||||
|
||||
GameConfig->DoGameSetup("Doom");
|
||||
M_SaveDefaults(NULL);
|
||||
|
@ -427,7 +427,7 @@ static void RestartWithParameters(const char* iwadPath, NSString* parameters)
|
|||
|
||||
[arguments addObject:@"-wad_picker_restart"];
|
||||
[arguments addObject:@"-iwad"];
|
||||
[arguments addObject:[NSString stringWithUTF8String:iwadPath]];
|
||||
[arguments addObject:[NSString stringWithUTF8String:wad.Path]];
|
||||
|
||||
for (int i = 1, count = Args->NumArgs(); i < count; ++i)
|
||||
{
|
||||
|
@ -477,7 +477,7 @@ int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad
|
|||
{
|
||||
if (0 != [parametersToAppend length])
|
||||
{
|
||||
RestartWithParameters(wads[ret].Path, parametersToAppend);
|
||||
RestartWithParameters(wads[ret], parametersToAppend);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
8692
src/posix/zdoom.xpm
8692
src/posix/zdoom.xpm
File diff suppressed because it is too large
Load diff
|
@ -49,7 +49,7 @@ struct FRenderer
|
|||
virtual void OnModeSet () {}
|
||||
virtual void SetClearColor(int color) = 0;
|
||||
virtual void Init() = 0;
|
||||
virtual void RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, int fov) = 0;
|
||||
virtual void RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, double fov) = 0;
|
||||
virtual void PreprocessLevel() {}
|
||||
virtual void CleanLevelData() {}
|
||||
virtual bool RequireGLNodes() { return false; }
|
||||
|
|
|
@ -1014,7 +1014,7 @@ void R_SetupFrame (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, AActor
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void FCanvasTextureInfo::Add (AActor *viewpoint, FTextureID picnum, int fov)
|
||||
void FCanvasTextureInfo::Add (AActor *viewpoint, FTextureID picnum, double fov)
|
||||
{
|
||||
FCanvasTextureInfo *probe;
|
||||
FCanvasTexture *texture;
|
||||
|
@ -1062,7 +1062,7 @@ DEFINE_ACTION_FUNCTION(_TexMan, SetCameraToTexture)
|
|||
PARAM_PROLOGUE;
|
||||
PARAM_OBJECT(viewpoint, AActor);
|
||||
PARAM_STRING(texturename); // [ZZ] there is no point in having this as FTextureID because it's easier to refer to a cameratexture by name and it isn't executed too often to cache it.
|
||||
PARAM_INT(fov);
|
||||
PARAM_FLOAT(fov);
|
||||
FTextureID textureid = TexMan.CheckForTexture(texturename, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable);
|
||||
FCanvasTextureInfo::Add(viewpoint, textureid, fov);
|
||||
return 0;
|
||||
|
@ -1150,7 +1150,7 @@ void FCanvasTextureInfo::Serialize(FSerializer &arc)
|
|||
if (arc.BeginArray("canvastextures"))
|
||||
{
|
||||
AActor *viewpoint = nullptr;
|
||||
int fov;
|
||||
double fov;
|
||||
FTextureID picnum;
|
||||
while (arc.BeginObject(nullptr))
|
||||
{
|
||||
|
|
|
@ -136,9 +136,9 @@ struct FCanvasTextureInfo
|
|||
TObjPtr<AActor*> Viewpoint;
|
||||
FCanvasTexture *Texture;
|
||||
FTextureID PicNum;
|
||||
int FOV;
|
||||
double FOV;
|
||||
|
||||
static void Add (AActor *viewpoint, FTextureID picnum, int fov);
|
||||
static void Add (AActor *viewpoint, FTextureID picnum, double fov);
|
||||
static void UpdateAll ();
|
||||
static void EmptyList ();
|
||||
static void Serialize(FSerializer &arc);
|
||||
|
|
|
@ -25,63 +25,70 @@
|
|||
#include "c_dispatch.h"
|
||||
#include "c_cvars.h"
|
||||
|
||||
CUSTOM_CVAR (Int, vid_scalemode, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
#define NUMSCALEMODES 5
|
||||
|
||||
namespace
|
||||
{
|
||||
if (self < 0 || self > 6)
|
||||
struct v_ScaleTable
|
||||
{
|
||||
self = 0;
|
||||
bool isValid;
|
||||
bool isLinear;
|
||||
uint32_t(*GetScaledWidth)(uint32_t Width);
|
||||
uint32_t(*GetScaledHeight)(uint32_t Height);
|
||||
bool isScaled43;
|
||||
};
|
||||
v_ScaleTable vScaleTable[NUMSCALEMODES] =
|
||||
{
|
||||
// isValid, isLinear, GetScaledWidth(), GetScaledHeight(), isScaled43
|
||||
{ true, false, [](uint32_t Width)->uint32_t { return Width; }, [](uint32_t Height)->uint32_t { return Height; }, false }, // 0 - Native
|
||||
{ true, true, [](uint32_t Width)->uint32_t { return Width; }, [](uint32_t Height)->uint32_t { return Height; }, false }, // 1 - Native (Linear)
|
||||
{ true, false, [](uint32_t Width)->uint32_t { return 320; }, [](uint32_t Height)->uint32_t { return 200; }, true }, // 2 - 320x200
|
||||
{ true, false, [](uint32_t Width)->uint32_t { return 640; }, [](uint32_t Height)->uint32_t { return 400; }, true }, // 3 - 640x400
|
||||
{ true, true, [](uint32_t Width)->uint32_t { return 1280; }, [](uint32_t Height)->uint32_t { return 800; }, true }, // 4 - 1280x800
|
||||
};
|
||||
bool isOutOfBounds(int x)
|
||||
{
|
||||
return (x < 0 || x >= NUMSCALEMODES || vScaleTable[x].isValid == false);
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, vid_scalefactor, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self <= 0.0 || self > 2.0)
|
||||
self = 1.0;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, vid_scalemode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (isOutOfBounds(self))
|
||||
self = 0;
|
||||
}
|
||||
|
||||
bool ViewportLinearScale()
|
||||
{
|
||||
switch(vid_scalemode)
|
||||
{
|
||||
default: return false;
|
||||
case 4:
|
||||
case 5:
|
||||
case 6: return true;
|
||||
}
|
||||
if (isOutOfBounds(vid_scalemode))
|
||||
vid_scalemode = 0;
|
||||
// vid_scalefactor > 1 == forced linear scale
|
||||
return (vid_scalefactor > 1.0) ? true : vScaleTable[vid_scalemode].isLinear;
|
||||
}
|
||||
|
||||
int ViewportScaledWidth(int width)
|
||||
{
|
||||
switch (vid_scalemode)
|
||||
{
|
||||
default:
|
||||
case 0: return width;
|
||||
case 1: return 320;
|
||||
case 2: return 640;
|
||||
case 3: return (int)roundf(width * 0.5f);
|
||||
case 4: return (int)roundf(width * 0.75f);
|
||||
case 5: return width * 2;
|
||||
case 6: return 1280;
|
||||
}
|
||||
if (isOutOfBounds(vid_scalemode))
|
||||
vid_scalemode = 0;
|
||||
return vScaleTable[vid_scalemode].GetScaledWidth((int)((float)width * vid_scalefactor));
|
||||
}
|
||||
|
||||
int ViewportScaledHeight(int height)
|
||||
{
|
||||
switch (vid_scalemode)
|
||||
{
|
||||
default:
|
||||
case 0: return height;
|
||||
case 1: return 200;
|
||||
case 2: return 400;
|
||||
case 3: return (int)roundf(height * 0.5f);
|
||||
case 4: return (int)roundf(height * 0.75f);
|
||||
case 5: return height * 2;
|
||||
case 6: return 800;
|
||||
}
|
||||
if (isOutOfBounds(vid_scalemode))
|
||||
vid_scalemode = 0;
|
||||
return vScaleTable[vid_scalemode].GetScaledHeight((int)((float)height * vid_scalefactor));
|
||||
}
|
||||
|
||||
bool ViewportIsScaled43()
|
||||
{
|
||||
switch (vid_scalemode)
|
||||
{
|
||||
default: return false;
|
||||
case 1:
|
||||
case 2:
|
||||
case 6: return true;
|
||||
}
|
||||
if (isOutOfBounds(vid_scalemode))
|
||||
vid_scalemode = 0;
|
||||
return vScaleTable[vid_scalemode].isScaled43;
|
||||
}
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ FxLocalVariableDeclaration *FCompileContext::FindLocalVariable(FName name)
|
|||
|
||||
static PContainerType *FindContainerType(FName name, FCompileContext &ctx)
|
||||
{
|
||||
auto sym = ctx.Class->Symbols.FindSymbol(name, true);
|
||||
auto sym = ctx.Class != nullptr? ctx.Class->Symbols.FindSymbol(name, true) : nullptr;
|
||||
if (sym == nullptr) sym = ctx.CurGlobals->Symbols.FindSymbol(name, true);
|
||||
if (sym && sym->IsKindOf(RUNTIME_CLASS(PSymbolType)))
|
||||
{
|
||||
|
@ -11101,7 +11101,7 @@ ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FxMultiNameState::FxMultiNameState(const char *_statestring, const FScriptPosition &pos)
|
||||
FxMultiNameState::FxMultiNameState(const char *_statestring, const FScriptPosition &pos, PClassActor *checkclass)
|
||||
:FxExpression(EFX_MultiNameState, pos)
|
||||
{
|
||||
FName scopename;
|
||||
|
@ -11119,7 +11119,7 @@ FxMultiNameState::FxMultiNameState(const char *_statestring, const FScriptPositi
|
|||
}
|
||||
names = MakeStateNameList(statestring);
|
||||
names.Insert(0, scopename);
|
||||
scope = nullptr;
|
||||
scope = checkclass;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -11135,8 +11135,8 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx)
|
|||
int symlabel;
|
||||
|
||||
auto vclass = PType::toClass(ctx.Class);
|
||||
assert(vclass != nullptr);
|
||||
auto clstype = ValidateActor(vclass->Descriptor);
|
||||
//assert(vclass != nullptr);
|
||||
auto clstype = vclass == nullptr? nullptr : ValidateActor(vclass->Descriptor);
|
||||
|
||||
if (names[0] == NAME_None)
|
||||
{
|
||||
|
|
|
@ -2089,7 +2089,7 @@ class FxMultiNameState : public FxExpression
|
|||
TArray<FName> names;
|
||||
public:
|
||||
|
||||
FxMultiNameState(const char *statestring, const FScriptPosition &pos);
|
||||
FxMultiNameState(const char *statestring, const FScriptPosition &pos, PClassActor *checkclass = nullptr);
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
};
|
||||
|
||||
|
|
|
@ -1280,3 +1280,16 @@ DEFINE_ACTION_FUNCTION(FStringStruct, ToLower)
|
|||
self->ToLower();
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FStringStruct, ToInt)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
PARAM_INT_DEF(base);
|
||||
ACTION_RETURN_INT(self->ToLong(base));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FStringStruct, ToDouble)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
ACTION_RETURN_FLOAT(self->ToDouble());
|
||||
}
|
||||
|
|
|
@ -2247,6 +2247,7 @@ bool PStruct::ReadValue(FSerializer &ar, const char *key, void *addr) const
|
|||
|
||||
PField *PStruct::AddField(FName name, PType *type, uint32_t flags)
|
||||
{
|
||||
assert(type->Size > 0);
|
||||
return Symbols.AddField(name, type, flags, Size, &Align);
|
||||
}
|
||||
|
||||
|
|
|
@ -1298,6 +1298,11 @@ bool ZCCCompiler::CompileFields(PContainerType *type, TArray<ZCC_VarDeclarator *
|
|||
auto name = field->Names;
|
||||
do
|
||||
{
|
||||
if (fieldtype->Size == 0 && !(varflags & VARF_Native)) // Size not known yet.
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (AddTreeNode(name->Name, name, TreeNodes, !forstruct))
|
||||
{
|
||||
auto thisfieldtype = fieldtype;
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
|
||||
#include "i_midi_win32.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "i_musicinterns.h"
|
||||
#include "c_cvars.h"
|
||||
|
@ -46,6 +48,7 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <wordexp.h>
|
||||
#include <glob.h>
|
||||
#include <signal.h>
|
||||
|
||||
|
@ -81,14 +84,16 @@ protected:
|
|||
HANDLE ReadWavePipe;
|
||||
HANDLE WriteWavePipe;
|
||||
HANDLE ChildProcess;
|
||||
FString CommandLine;
|
||||
size_t LoopPos;
|
||||
bool Validated;
|
||||
bool ValidateTimidity();
|
||||
#else // _WIN32
|
||||
int WavePipe[2];
|
||||
pid_t ChildProcess;
|
||||
#endif
|
||||
FString CommandLine;
|
||||
size_t LoopPos;
|
||||
FString ExeName;
|
||||
bool Looping;
|
||||
|
||||
static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata);
|
||||
#ifdef _WIN32
|
||||
|
@ -118,6 +123,7 @@ CUSTOM_CVAR(String, timidity_exe, "timidity", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
|||
}
|
||||
|
||||
CVAR (String, timidity_extargs, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // extra args to pass to Timidity
|
||||
CVAR (String, timidity_config, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (String, timidity_chorus, "0", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (String, timidity_reverb, "0", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, timidity_stereo, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
@ -137,9 +143,9 @@ CUSTOM_CVAR (Float, timidity_mastervolume, 1.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|||
|
||||
CUSTOM_CVAR (Int, timidity_pipe, 90, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{ // pipe size in ms
|
||||
if (timidity_pipe < 0)
|
||||
{ // a negative size makes no sense
|
||||
timidity_pipe = 0;
|
||||
if (self < 20)
|
||||
{ // Don't allow pipes less than 20ms
|
||||
self = 20;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,20 +168,30 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args)
|
|||
#ifdef _WIN32
|
||||
ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE),
|
||||
ChildProcess(INVALID_HANDLE_VALUE),
|
||||
Validated(false)
|
||||
Validated(false),
|
||||
#else
|
||||
ChildProcess(-1)
|
||||
ChildProcess(-1),
|
||||
#endif
|
||||
Looping(false)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
WavePipe[0] = WavePipe[1] = -1;
|
||||
#endif
|
||||
|
||||
if (args == NULL || *args == 0) args = timidity_exe;
|
||||
ExeName = args;
|
||||
|
||||
#ifdef _WIN32
|
||||
CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ",
|
||||
args, *timidity_extargs,
|
||||
*timidity_chorus, *timidity_reverb, *timidity_frequency);
|
||||
if (**timidity_config != '\0')
|
||||
{
|
||||
CommandLine += "-c \"";
|
||||
CommandLine += timidity_config;
|
||||
CommandLine += "\" ";
|
||||
}
|
||||
#endif
|
||||
|
||||
if (DiskName == NULL)
|
||||
{
|
||||
|
@ -229,14 +245,17 @@ bool TimidityPPMIDIDevice::Preprocess(MIDIStreamer *song, bool looping)
|
|||
bool success;
|
||||
FILE *f;
|
||||
|
||||
if (CommandLine.IsEmpty())
|
||||
if (ExeName.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Tell TiMidity++ whether it should loop or not
|
||||
#ifdef _WIN32
|
||||
CommandLine.LockBuffer()[LoopPos] = looping ? 'l' : ' ';
|
||||
CommandLine.UnlockBuffer();
|
||||
#endif
|
||||
Looping = looping;
|
||||
|
||||
// Write MIDI song to temporary file
|
||||
song->CreateSMF(midi, looping ? 0 : 1);
|
||||
|
@ -298,46 +317,31 @@ int TimidityPPMIDIDevice::Open(MidiCallback callback, void *userdata)
|
|||
#endif
|
||||
{
|
||||
Printf(PRINT_BOLD, "Could not create a data pipe for TiMidity++.\n");
|
||||
pipeSize = 0;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
|
||||
Stream = GSnd->CreateStream(FillStream, pipeSize,
|
||||
(timidity_stereo ? 0 : SoundStream::Mono) |
|
||||
(timidity_8bit ? SoundStream::Bits8 : 0),
|
||||
timidity_frequency, this);
|
||||
if (Stream == NULL)
|
||||
{
|
||||
Stream = GSnd->CreateStream(FillStream, pipeSize,
|
||||
(timidity_stereo ? 0 : SoundStream::Mono) |
|
||||
(timidity_8bit ? SoundStream::Bits8 : 0),
|
||||
timidity_frequency, this);
|
||||
if (Stream == NULL)
|
||||
{
|
||||
Printf(PRINT_BOLD, "Could not create music stream.\n");
|
||||
pipeSize = 0;
|
||||
Printf(PRINT_BOLD, "Could not create music stream.\n");
|
||||
#ifdef _WIN32
|
||||
CloseHandle(WriteWavePipe);
|
||||
CloseHandle(ReadWavePipe);
|
||||
ReadWavePipe = WriteWavePipe = INVALID_HANDLE_VALUE;
|
||||
CloseHandle(WriteWavePipe);
|
||||
CloseHandle(ReadWavePipe);
|
||||
ReadWavePipe = WriteWavePipe = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
close(WavePipe[1]);
|
||||
close(WavePipe[0]);
|
||||
WavePipe[0] = WavePipe[1] = -1;
|
||||
close(WavePipe[1]);
|
||||
close(WavePipe[0]);
|
||||
WavePipe[0] = WavePipe[1] = -1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (pipeSize == 0)
|
||||
{
|
||||
Printf(PRINT_BOLD, "If your soundcard cannot play more than one\n"
|
||||
"wave at a time, you will hear no music.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
CommandLine += "-o - -Ors";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (pipeSize == 0)
|
||||
{
|
||||
CommandLine += "-Od";
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
CommandLine += "-o - -Ors";
|
||||
CommandLine += timidity_stereo ? 'S' : 'M';
|
||||
CommandLine += timidity_8bit ? '8' : '1';
|
||||
if (timidity_byteswap)
|
||||
|
@ -349,6 +353,7 @@ int TimidityPPMIDIDevice::Open(MidiCallback callback, void *userdata)
|
|||
|
||||
CommandLine += " -idl ";
|
||||
CommandLine += DiskName.GetName();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -456,6 +461,7 @@ bool TimidityPPMIDIDevice::ValidateTimidity()
|
|||
|
||||
bool TimidityPPMIDIDevice::LaunchTimidity ()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (CommandLine.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
|
@ -463,7 +469,6 @@ bool TimidityPPMIDIDevice::LaunchTimidity ()
|
|||
|
||||
DPrintf (DMSG_NOTIFY, "cmd: \x1cG%s\n", CommandLine.GetChars());
|
||||
|
||||
#ifdef _WIN32
|
||||
STARTUPINFO startup = { sizeof(startup), };
|
||||
PROCESS_INFORMATION procInfo;
|
||||
|
||||
|
@ -509,6 +514,11 @@ bool TimidityPPMIDIDevice::LaunchTimidity ()
|
|||
}
|
||||
return false;
|
||||
#else
|
||||
if (ExeName.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (WavePipe[0] != -1 && WavePipe[1] == -1 && Stream != NULL)
|
||||
{
|
||||
// Timidity was previously launched, so the write end of the pipe
|
||||
|
@ -523,78 +533,55 @@ bool TimidityPPMIDIDevice::LaunchTimidity ()
|
|||
}
|
||||
|
||||
int forkres;
|
||||
wordexp_t words;
|
||||
glob_t glb;
|
||||
|
||||
// Get timidity executable path
|
||||
int spaceIdx = 0;
|
||||
int spaceInExePathCount = -1;
|
||||
FString TimidityExe;
|
||||
do
|
||||
const char *exename = "timidity"; // Fallback default
|
||||
glob(ExeName.GetChars(), 0, NULL, &glb);
|
||||
if(glb.gl_pathc != 0)
|
||||
exename = glb.gl_pathv[0];
|
||||
// Get user-defined extra args
|
||||
wordexp(timidity_extargs, &words, WRDE_NOCMD);
|
||||
|
||||
std::string chorusarg = std::string("-EFchorus=") + *timidity_chorus;
|
||||
std::string reverbarg = std::string("-EFreverb=") + *timidity_reverb;
|
||||
std::string sratearg = std::string("-s") + std::to_string(*timidity_frequency);
|
||||
std::string outfilearg = "-o"; // An extra "-" is added later
|
||||
std::string outmodearg = "-Or";
|
||||
outmodearg += timidity_8bit ? "u8" : "s1";
|
||||
outmodearg += timidity_stereo ? "S" : "M";
|
||||
if(timidity_byteswap) outmodearg += "x";
|
||||
std::string ifacearg = "-id";
|
||||
if(Looping) ifacearg += "l";
|
||||
|
||||
std::vector<const char*> arglist;
|
||||
arglist.push_back(exename);
|
||||
for(size_t i = 0;i < words.we_wordc;i++)
|
||||
arglist.push_back(words.we_wordv[i]);
|
||||
if(**timidity_config != '\0')
|
||||
{
|
||||
spaceIdx = CommandLine.IndexOf(' ', spaceIdx);
|
||||
TimidityExe = CommandLine.Left(spaceIdx);
|
||||
glob(TimidityExe.GetChars(), 0, NULL, &glb);
|
||||
spaceIdx += 1;
|
||||
spaceInExePathCount += 1;
|
||||
} while (spaceIdx != 0 && glb.gl_pathc == 0);
|
||||
if (spaceIdx == 0)
|
||||
{
|
||||
TimidityExe = FString("timidity"); // Maybe it's in your PATH?
|
||||
spaceInExePathCount = 0;
|
||||
arglist.push_back("-c");
|
||||
arglist.push_back(timidity_config);
|
||||
}
|
||||
globfree(&glb);
|
||||
arglist.push_back(chorusarg.c_str());
|
||||
arglist.push_back(reverbarg.c_str());
|
||||
arglist.push_back(sratearg.c_str());
|
||||
arglist.push_back(outfilearg.c_str());
|
||||
arglist.push_back("-");
|
||||
arglist.push_back(outmodearg.c_str());
|
||||
arglist.push_back(ifacearg.c_str());
|
||||
arglist.push_back(DiskName.GetName());
|
||||
|
||||
int strCount = 1;
|
||||
for (spaceIdx = 0; spaceIdx < CommandLine.Len(); spaceIdx++)
|
||||
{
|
||||
if (CommandLine[spaceIdx] == ' ')
|
||||
{
|
||||
++strCount;
|
||||
if (CommandLine[spaceIdx+1] == ' ')
|
||||
{
|
||||
--strCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
strCount -= spaceInExePathCount;
|
||||
|
||||
char** TimidityArgs = new char*[strCount + 1];
|
||||
TimidityArgs[strCount] = NULL;
|
||||
|
||||
spaceIdx = CommandLine.IndexOf(' ');
|
||||
int curSpace = spaceIdx, i = 1;
|
||||
|
||||
TimidityArgs[0] = new char[TimidityExe.Len() + 1];
|
||||
TimidityArgs[0][TimidityExe.Len()] = 0;
|
||||
strcpy(TimidityArgs[0], TimidityExe.GetChars());
|
||||
|
||||
int argLen;
|
||||
while (curSpace != -1)
|
||||
{
|
||||
curSpace = CommandLine.IndexOf(' ', spaceIdx);
|
||||
if (curSpace != spaceIdx)
|
||||
{
|
||||
argLen = curSpace - spaceIdx + 1;
|
||||
if (argLen < 0)
|
||||
{
|
||||
argLen = CommandLine.Len() - curSpace;
|
||||
}
|
||||
TimidityArgs[i] = new char[argLen];
|
||||
TimidityArgs[i][argLen-1] = 0;
|
||||
strcpy(TimidityArgs[i], CommandLine.Mid(spaceIdx, curSpace - spaceIdx).GetChars());
|
||||
i += 1;
|
||||
}
|
||||
spaceIdx = curSpace + 1;
|
||||
}
|
||||
|
||||
DPrintf(DMSG_NOTIFY, "Timidity EXE: \x1cG%s\n", TimidityExe.GetChars());
|
||||
for (i = 0; i < strCount; i++)
|
||||
{
|
||||
DPrintf(DMSG_NOTIFY, "arg %d: \x1cG%s\n", i, TimidityArgs[i]);
|
||||
}
|
||||
DPrintf(DMSG_NOTIFY, "Timidity EXE: \x1cG%s\n", exename);
|
||||
int i = 1;
|
||||
std::for_each(arglist.begin()+1, arglist.end(),
|
||||
[&i](const char *arg)
|
||||
{ DPrintf(DMSG_NOTIFY, "arg %d: \x1cG%s\n", i++, arg); }
|
||||
);
|
||||
arglist.push_back(nullptr);
|
||||
|
||||
forkres = fork ();
|
||||
|
||||
if (forkres == 0)
|
||||
{
|
||||
close (WavePipe[0]);
|
||||
|
@ -603,7 +590,7 @@ bool TimidityPPMIDIDevice::LaunchTimidity ()
|
|||
// freopen ("/dev/null", "w", stderr);
|
||||
close (WavePipe[1]);
|
||||
|
||||
execvp (TimidityExe.GetChars(), TimidityArgs);
|
||||
execvp (exename, const_cast<char*const*>(arglist.data()));
|
||||
fprintf(stderr,"execvp failed: %s\n", strerror(errno));
|
||||
_exit (0); // if execvp succeeds, we never get here
|
||||
}
|
||||
|
@ -624,6 +611,7 @@ bool TimidityPPMIDIDevice::LaunchTimidity ()
|
|||
}*/
|
||||
}
|
||||
|
||||
wordfree(&words);
|
||||
globfree (&glb);
|
||||
return ChildProcess != -1;
|
||||
#endif // _WIN32
|
||||
|
@ -666,7 +654,6 @@ bool TimidityPPMIDIDevice::FillStream(SoundStream *stream, void *buff, int len,
|
|||
}
|
||||
}
|
||||
#else
|
||||
ssize_t got;
|
||||
fd_set rfds;
|
||||
struct timeval tv;
|
||||
|
||||
|
@ -691,11 +678,26 @@ bool TimidityPPMIDIDevice::FillStream(SoundStream *stream, void *buff, int len,
|
|||
}
|
||||
// fprintf(stderr,"something\n");
|
||||
|
||||
got = read(song->WavePipe[0], (uint8_t *)buff, len);
|
||||
if (got < len)
|
||||
{
|
||||
memset((uint8_t *)buff+got, 0, len-got);
|
||||
}
|
||||
ssize_t got = 0;
|
||||
do {
|
||||
ssize_t r = read(song->WavePipe[0], (uint8_t*)buff+got, len-got);
|
||||
if(r < 0)
|
||||
{
|
||||
if(errno == EWOULDBLOCK || errno == EAGAIN)
|
||||
{
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(song->WavePipe[0], &rfds);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 50;
|
||||
select(1, &rfds, NULL, NULL, &tv);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
got += r;
|
||||
} while(got < len);
|
||||
if(got < len)
|
||||
memset((uint8_t*)buff+got, 0, len-got);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
@ -755,8 +757,7 @@ int TimidityPPMIDIDevice::Resume()
|
|||
{
|
||||
if (LaunchTimidity())
|
||||
{
|
||||
// Assume success if not mixing with the sound system
|
||||
if (Stream == NULL || Stream->Play(true, timidity_mastervolume))
|
||||
if (Stream != NULL && Stream->Play(true, timidity_mastervolume))
|
||||
{
|
||||
Started = true;
|
||||
return 0;
|
||||
|
|
|
@ -61,6 +61,9 @@ enum
|
|||
STAT_MAPMARKER, // Map marker actors
|
||||
STAT_DLIGHT,
|
||||
|
||||
STAT_USER = 70,
|
||||
STAT_USER_MAX = 90,
|
||||
|
||||
STAT_DEFAULT = 100, // Thinkers go here unless specified otherwise.
|
||||
STAT_SECTOREFFECT, // All sector effects that cause floor and ceiling movement
|
||||
STAT_ACTORMOVER, // actor movers
|
||||
|
|
|
@ -1398,9 +1398,9 @@ namespace swrenderer
|
|||
{
|
||||
uint32_t val = colormap[source[frac >> FRACBITS]] << 2;
|
||||
|
||||
int r = (palette[*dest].r * (255-val) + palette[color].r * val) >> 10;
|
||||
int g = (palette[*dest].g * (255-val) + palette[color].g * val) >> 10;
|
||||
int b = (palette[*dest].b * (255-val) + palette[color].b * val) >> 10;
|
||||
int r = (palette[*dest].r * (256-val) + palette[color].r * val) >> 10;
|
||||
int g = (palette[*dest].g * (256-val) + palette[color].g * val) >> 10;
|
||||
int b = (palette[*dest].b * (256-val) + palette[color].b * val) >> 10;
|
||||
*dest = RGB256k.RGB[clamp(r,0,63)][clamp(g,0,63)][clamp(b,0,63)];
|
||||
|
||||
dest += pitch;
|
||||
|
@ -1441,9 +1441,9 @@ namespace swrenderer
|
|||
{
|
||||
uint32_t val = colormap[source[frac >> FRACBITS]] << 2;
|
||||
|
||||
int r = (palette[*dest].r * (255) + palette[color].r * val) >> 10;
|
||||
int g = (palette[*dest].g * (255) + palette[color].g * val) >> 10;
|
||||
int b = (palette[*dest].b * (255) + palette[color].b * val) >> 10;
|
||||
int r = (palette[*dest].r * (256) + palette[color].r * val) >> 10;
|
||||
int g = (palette[*dest].g * (256) + palette[color].g * val) >> 10;
|
||||
int b = (palette[*dest].b * (256) + palette[color].b * val) >> 10;
|
||||
*dest = RGB256k.RGB[clamp(r,0,63)][clamp(g,0,63)][clamp(b,0,63)];
|
||||
|
||||
dest += pitch;
|
||||
|
@ -2151,8 +2151,8 @@ namespace swrenderer
|
|||
}
|
||||
else
|
||||
{
|
||||
uint8_t srcwidth = _srcwidth;
|
||||
uint8_t srcheight = _srcheight;
|
||||
uint32_t srcwidth = _srcwidth;
|
||||
uint32_t srcheight = _srcheight;
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -2222,8 +2222,8 @@ namespace swrenderer
|
|||
}
|
||||
else
|
||||
{
|
||||
uint8_t srcwidth = _srcwidth;
|
||||
uint8_t srcheight = _srcheight;
|
||||
uint32_t srcwidth = _srcwidth;
|
||||
uint32_t srcheight = _srcheight;
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -2298,8 +2298,8 @@ namespace swrenderer
|
|||
}
|
||||
else
|
||||
{
|
||||
uint8_t srcwidth = _srcwidth;
|
||||
uint8_t srcheight = _srcheight;
|
||||
uint32_t srcwidth = _srcwidth;
|
||||
uint32_t srcheight = _srcheight;
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -2338,8 +2338,8 @@ namespace swrenderer
|
|||
}
|
||||
else
|
||||
{
|
||||
uint8_t srcwidth = _srcwidth;
|
||||
uint8_t srcheight = _srcheight;
|
||||
uint32_t srcwidth = _srcwidth;
|
||||
uint32_t srcheight = _srcheight;
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -2421,8 +2421,8 @@ namespace swrenderer
|
|||
}
|
||||
else
|
||||
{
|
||||
uint8_t srcwidth = _srcwidth;
|
||||
uint8_t srcheight = _srcheight;
|
||||
uint32_t srcwidth = _srcwidth;
|
||||
uint32_t srcheight = _srcheight;
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -2474,8 +2474,8 @@ namespace swrenderer
|
|||
}
|
||||
else
|
||||
{
|
||||
uint8_t srcwidth = _srcwidth;
|
||||
uint8_t srcheight = _srcheight;
|
||||
uint32_t srcwidth = _srcwidth;
|
||||
uint32_t srcheight = _srcheight;
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -2559,8 +2559,8 @@ namespace swrenderer
|
|||
}
|
||||
else
|
||||
{
|
||||
uint8_t srcwidth = _srcwidth;
|
||||
uint8_t srcheight = _srcheight;
|
||||
uint32_t srcwidth = _srcwidth;
|
||||
uint32_t srcheight = _srcheight;
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -2603,8 +2603,8 @@ namespace swrenderer
|
|||
}
|
||||
else
|
||||
{
|
||||
uint8_t srcwidth = _srcwidth;
|
||||
uint8_t srcheight = _srcheight;
|
||||
uint32_t srcwidth = _srcwidth;
|
||||
uint32_t srcheight = _srcheight;
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -2689,8 +2689,8 @@ namespace swrenderer
|
|||
}
|
||||
else
|
||||
{
|
||||
uint8_t srcwidth = _srcwidth;
|
||||
uint8_t srcheight = _srcheight;
|
||||
uint32_t srcwidth = _srcwidth;
|
||||
uint32_t srcheight = _srcheight;
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -2746,8 +2746,8 @@ namespace swrenderer
|
|||
}
|
||||
else
|
||||
{
|
||||
uint8_t srcwidth = _srcwidth;
|
||||
uint8_t srcheight = _srcheight;
|
||||
uint32_t srcwidth = _srcwidth;
|
||||
uint32_t srcheight = _srcheight;
|
||||
|
||||
do
|
||||
{
|
||||
|
|
|
@ -76,7 +76,7 @@ namespace swrenderer
|
|||
|
||||
while (node)
|
||||
{
|
||||
if (!(node->lightsource->flags2&MF2_DORMANT))
|
||||
if (!(node->lightsource->flags2&MF2_DORMANT) && (height.PointOnSide(node->lightsource->Pos()) > 0))
|
||||
{
|
||||
bool found = false;
|
||||
VisiblePlaneLight *light_node = lights;
|
||||
|
|
|
@ -272,7 +272,7 @@ void FSoftwareRenderer::SetClearColor(int color)
|
|||
mScene.SetClearColor(color);
|
||||
}
|
||||
|
||||
void FSoftwareRenderer::RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, int fov)
|
||||
void FSoftwareRenderer::RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, double fov)
|
||||
{
|
||||
auto renderTarget = r_polyrenderer ? PolyRenderer::Instance()->RenderTarget : mScene.MainThread()->Viewport->RenderTarget;
|
||||
auto &cameraViewpoint = r_polyrenderer ? PolyRenderer::Instance()->Viewpoint : mScene.MainThread()->Viewport->viewpoint;
|
||||
|
@ -290,7 +290,7 @@ void FSoftwareRenderer::RenderTextureView (FCanvasTexture *tex, AActor *viewpoin
|
|||
CameraLight savedCameraLight = *CameraLight::Instance();
|
||||
|
||||
DAngle savedfov = cameraViewpoint.FieldOfView;
|
||||
R_SetFOV (cameraViewpoint, (double)fov);
|
||||
R_SetFOV (cameraViewpoint, fov);
|
||||
|
||||
if (r_polyrenderer)
|
||||
PolyRenderer::Instance()->RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), tex->bFirstUpdate);
|
||||
|
@ -382,12 +382,16 @@ void FSoftwareRenderer::CleanLevelData()
|
|||
|
||||
uint32_t FSoftwareRenderer::GetCaps()
|
||||
{
|
||||
ActorRenderFeatureFlags FlagSet = RFF_UNCLIPPEDTEX;
|
||||
ActorRenderFeatureFlags FlagSet = 0;
|
||||
|
||||
if (r_polyrenderer)
|
||||
FlagSet |= RFF_POLYGONAL | RFF_TILTPITCH;
|
||||
else if (r_drawvoxels)
|
||||
FlagSet |= RFF_VOXELS;
|
||||
FlagSet |= RFF_POLYGONAL | RFF_TILTPITCH | RFF_SLOPE3DFLOORS;
|
||||
else
|
||||
{
|
||||
FlagSet |= RFF_UNCLIPPEDTEX;
|
||||
if (r_drawvoxels)
|
||||
FlagSet |= RFF_VOXELS;
|
||||
}
|
||||
|
||||
if (screen && screen->IsBgra())
|
||||
FlagSet |= RFF_TRUECOLOR;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue