mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-26 05:51:20 +00:00
Merge branch 'master' into reverbedit
This commit is contained in:
commit
7e45535669
87 changed files with 1513 additions and 1810 deletions
|
@ -733,6 +733,7 @@ set ( SWRENDER_SOURCES
|
|||
swrenderer/things/r_sprite.cpp
|
||||
swrenderer/things/r_wallsprite.cpp
|
||||
swrenderer/things/r_decal.cpp
|
||||
swrenderer/things/r_model.cpp
|
||||
swrenderer/plane/r_visibleplane.cpp
|
||||
swrenderer/plane/r_visibleplanelist.cpp
|
||||
swrenderer/plane/r_skyplane.cpp
|
||||
|
@ -1167,6 +1168,7 @@ set (PCH_SOURCES
|
|||
events.cpp
|
||||
GuillotineBinPack.cpp
|
||||
SkylineBinPack.cpp
|
||||
tmpfileplus.cpp
|
||||
)
|
||||
|
||||
enable_precompiled_headers( g_pch.h PCH_SOURCES )
|
||||
|
@ -1181,7 +1183,6 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
|
|||
${PCH_SOURCES}
|
||||
x86.cpp
|
||||
strnatcmp.c
|
||||
tmpfileplus.c
|
||||
zstring.cpp
|
||||
math/asin.c
|
||||
math/atan.c
|
||||
|
|
|
@ -532,13 +532,9 @@ bool FCajunMaster::LoadBots ()
|
|||
DPrintf (DMSG_ERROR, "No " BOTFILENAME ", so no bots\n");
|
||||
return false;
|
||||
}
|
||||
try
|
||||
if (!sc.OpenFile(tmp))
|
||||
{
|
||||
sc.OpenFile(tmp);
|
||||
}
|
||||
catch (CRecoverableError &err)
|
||||
{
|
||||
Printf("%s. So no bots\n", err.GetMessage());
|
||||
Printf("Unable to open %s. So no bots\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -145,26 +145,6 @@ void ReplaceString (char **ptr, const char *str)
|
|||
*/
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Q_filelength
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int Q_filelength (FILE *f)
|
||||
{
|
||||
int pos;
|
||||
int end;
|
||||
|
||||
pos = ftell (f);
|
||||
fseek (f, 0, SEEK_END);
|
||||
end = ftell (f);
|
||||
fseek (f, pos, SEEK_SET);
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FileExists
|
||||
|
@ -175,13 +155,9 @@ int Q_filelength (FILE *f)
|
|||
|
||||
bool FileExists (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);
|
||||
bool isdir;
|
||||
bool res = DirEntryExists(filename, &isdir);
|
||||
return res && !isdir;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -194,13 +170,9 @@ bool FileExists (const char *filename)
|
|||
|
||||
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);
|
||||
bool isdir;
|
||||
bool res = DirEntryExists(filename, &isdir);
|
||||
return res && isdir;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -211,13 +183,16 @@ bool DirExists(const char *filename)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool DirEntryExists(const char *pathname)
|
||||
bool DirEntryExists(const char *pathname, bool *isdir)
|
||||
{
|
||||
if (isdir) *isdir = false;
|
||||
if (pathname == NULL || *pathname == 0)
|
||||
return false;
|
||||
|
||||
struct stat info;
|
||||
return stat(pathname, &info) == 0;
|
||||
bool res = stat(pathname, &info) == 0;
|
||||
if (isdir) *isdir = !!(info.st_mode & S_IFDIR);
|
||||
return res;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -570,7 +545,7 @@ void CreatePath(const char *fn)
|
|||
*p = '\0';
|
||||
}
|
||||
struct stat info;
|
||||
if (stat(copy, &info) == 0)
|
||||
if (DirEntryExists(copy))
|
||||
{
|
||||
if (info.st_mode & S_IFDIR)
|
||||
goto exists;
|
||||
|
@ -1029,10 +1004,7 @@ void ScanDirectory(TArray<FFileList> &list, const char *dirpath)
|
|||
FFileList *fl = &list[list.Reserve(1)];
|
||||
fl->Filename << dirpath << file->d_name;
|
||||
|
||||
struct stat fileStat;
|
||||
stat(fl->Filename, &fileStat);
|
||||
fl->isDirectory = S_ISDIR(fileStat.st_mode);
|
||||
|
||||
fl->isDirectory = DirExists(fl->Filename);
|
||||
if(fl->isDirectory)
|
||||
{
|
||||
FString newdir = fl->Filename;
|
||||
|
|
|
@ -18,10 +18,9 @@
|
|||
// the dec offsetof macro doesnt work very well...
|
||||
#define myoffsetof(type,identifier) ((size_t)&((type *)alignof(type))->identifier - alignof(type))
|
||||
|
||||
int Q_filelength (FILE *f);
|
||||
bool FileExists (const char *filename);
|
||||
bool DirExists(const char *filename);
|
||||
bool DirEntryExists (const char *pathname);
|
||||
bool DirEntryExists (const char *pathname, bool *isdir = nullptr);
|
||||
|
||||
extern FString progdir;
|
||||
|
||||
|
|
|
@ -2488,17 +2488,16 @@ bool D_LoadDehLump(int lumpnum)
|
|||
|
||||
bool D_LoadDehFile(const char *patchfile)
|
||||
{
|
||||
FILE *deh;
|
||||
FileReader fr;
|
||||
|
||||
deh = fopen(patchfile, "rb");
|
||||
if (deh != NULL)
|
||||
if (!fr.Open(patchfile))
|
||||
{
|
||||
PatchSize = Q_filelength(deh);
|
||||
PatchSize = fr.GetLength();
|
||||
|
||||
PatchName = copystring(patchfile);
|
||||
PatchFile = new char[PatchSize + 1];
|
||||
fread(PatchFile, 1, PatchSize, deh);
|
||||
fclose(deh);
|
||||
fr.Read(PatchFile, PatchSize);
|
||||
fr.Close();
|
||||
PatchFile[PatchSize] = '\0'; // terminate with a '\0' character
|
||||
return DoDehPatch();
|
||||
}
|
||||
|
|
|
@ -1946,13 +1946,11 @@ static FString CheckGameInfo(TArray<FString> & pwads)
|
|||
const char *filename = pwads[i];
|
||||
|
||||
// Does this exist? If so, is it a directory?
|
||||
struct stat info;
|
||||
if (stat(pwads[i], &info) != 0)
|
||||
if (!DirEntryExists(pwads[i], &isdir))
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "Could not stat %s\n", filename);
|
||||
continue;
|
||||
}
|
||||
isdir = (info.st_mode & S_IFDIR) != 0;
|
||||
|
||||
if (!isdir)
|
||||
{
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "version.h"
|
||||
#include "menu/menu.h"
|
||||
|
@ -2871,7 +2872,7 @@ CCMD (pings)
|
|||
int i;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i])
|
||||
Printf ("% 4d %s\n", currrecvtime[i] - lastrecvtime[i],
|
||||
Printf ("% 4" PRId64 " %s\n", currrecvtime[i] - lastrecvtime[i],
|
||||
players[i].userinfo.GetName());
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,11 @@
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FILE *FileReader::openfd(const char *filename)
|
||||
{
|
||||
return fopen(filename, "rb");
|
||||
}
|
||||
|
||||
FileReader::FileReader ()
|
||||
: File(NULL), Length(0), StartPos(0), FilePos(0), CloseOnDestruct(false)
|
||||
{
|
||||
|
@ -82,18 +87,23 @@ FileReader::FileReader (FILE *file, long length)
|
|||
FilePos = StartPos = ftell (file);
|
||||
}
|
||||
|
||||
FileReader::~FileReader ()
|
||||
FileReader::~FileReader()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void FileReader::Close()
|
||||
{
|
||||
if (CloseOnDestruct && File != NULL)
|
||||
{
|
||||
fclose (File);
|
||||
File = NULL;
|
||||
}
|
||||
File = NULL;
|
||||
}
|
||||
|
||||
bool FileReader::Open (const char *filename)
|
||||
{
|
||||
File = fopen (filename, "rb");
|
||||
File = openfd (filename);
|
||||
if (File == NULL) return false;
|
||||
FilePos = 0;
|
||||
StartPos = 0;
|
||||
|
@ -634,6 +644,30 @@ size_t FileWriter::Write(const void *buffer, size_t len)
|
|||
}
|
||||
}
|
||||
|
||||
long FileWriter::Tell()
|
||||
{
|
||||
if (File != NULL)
|
||||
{
|
||||
return ftell(File);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
long FileWriter::Seek(long offset, int mode)
|
||||
{
|
||||
if (File != NULL)
|
||||
{
|
||||
return fseek(File, offset, mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t FileWriter::Printf(const char *fmt, ...)
|
||||
{
|
||||
|
|
|
@ -93,12 +93,15 @@ public:
|
|||
|
||||
class FileReader : public FileReaderBase
|
||||
{
|
||||
protected:
|
||||
FILE *openfd(const char *filename);
|
||||
public:
|
||||
FileReader ();
|
||||
FileReader (const char *filename);
|
||||
FileReader (FILE *file);
|
||||
FileReader (FILE *file, long length);
|
||||
bool Open (const char *filename);
|
||||
void Close();
|
||||
virtual ~FileReader ();
|
||||
|
||||
virtual long Tell () const;
|
||||
|
@ -409,6 +412,8 @@ public:
|
|||
static FileWriter *Open(const char *filename);
|
||||
|
||||
virtual size_t Write(const void *buffer, size_t len);
|
||||
virtual long Tell();
|
||||
virtual long Seek(long offset, int mode);
|
||||
size_t Printf(const char *fmt, ...) GCCPRINTF(2,3);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -2798,7 +2798,17 @@ void G_DoPlayDemo (void)
|
|||
{
|
||||
FixPathSeperator (defdemoname);
|
||||
DefaultExtension (defdemoname, ".lmp");
|
||||
M_ReadFileMalloc (defdemoname, &demobuffer);
|
||||
FileReader fr;
|
||||
if (!fr.Open(defdemoname))
|
||||
{
|
||||
I_Error("Unable to open demo '%s'", defdemoname.GetChars());
|
||||
}
|
||||
auto len = fr.GetLength();
|
||||
demobuffer = (uint8_t*)M_Malloc(len);
|
||||
if (fr.Read(demobuffer, len) != len)
|
||||
{
|
||||
I_Error("Unable to read demo '%s'", defdemoname.GetChars());
|
||||
}
|
||||
}
|
||||
demo_p = demobuffer;
|
||||
|
||||
|
@ -2964,7 +2974,15 @@ bool G_CheckDemoStatus (void)
|
|||
formlen = demobuffer + 4;
|
||||
WriteLong (int(demo_p - demobuffer - 8), &formlen);
|
||||
|
||||
bool saved = M_WriteFile (demoname, demobuffer, int(demo_p - demobuffer));
|
||||
auto fw = FileWriter::Open(demoname);
|
||||
bool saved = false;
|
||||
if (fw != nullptr)
|
||||
{
|
||||
auto size = long(demo_p - demobuffer);
|
||||
saved = fw->Write(demobuffer, size) == size;
|
||||
delete fw;
|
||||
if (!saved) remove(demoname);
|
||||
}
|
||||
M_Free (demobuffer);
|
||||
demorecording = false;
|
||||
stoprecording = false;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -47,91 +47,16 @@ class CImage
|
|||
eConvSourceMemory = 11,
|
||||
eConvDestMemory = 12,
|
||||
|
||||
eSaveBmpFileOpen = 20,
|
||||
eSaveBmpFileWrite = 21,
|
||||
eSaveBmpSourceMemory = 22,
|
||||
eSaveBmpColorDepth = 23,
|
||||
|
||||
eLoadBmpFileOpen = 30,
|
||||
eLoadBmpFileRead = 31,
|
||||
eLoadBmpBadFormat = 32,
|
||||
eLoadBmpInit = 33,
|
||||
eLoadBmpColorDepth = 34,
|
||||
|
||||
eSaveTgaFileOpen = 40,
|
||||
eSaveTgaFileWrite = 41,
|
||||
eSaveTgaSourceMemory = 42,
|
||||
eSaveTgaColorDepth = 43,
|
||||
|
||||
eLoadTgaFileOpen = 50,
|
||||
eLoadTgaFileRead = 51,
|
||||
eLoadTgaBadFormat = 52,
|
||||
eLoadTgaInit = 53,
|
||||
eLoadTgaColorDepth = 54,
|
||||
|
||||
eLoadFilename = 60,
|
||||
eSaveFilename = 61,
|
||||
};
|
||||
|
||||
struct _BMPFILEHEADER
|
||||
{
|
||||
unsigned short bfType;
|
||||
long int bfSize, bfRes1, bfOffBits;
|
||||
};
|
||||
|
||||
struct _BMPIMAGEHEADEROLD
|
||||
{
|
||||
long int biSize;
|
||||
unsigned short biWidth, biHeight;
|
||||
unsigned short biPlanes, biBitCount;
|
||||
};
|
||||
|
||||
struct _BMPIMAGEHEADER
|
||||
{
|
||||
long int biSize, biWidth, biHeight;
|
||||
unsigned short biPlanes, biBitCount;
|
||||
long int biCompression, biSizeImage;
|
||||
long int biXPelsPerMeter, biYPelsPerMeter;
|
||||
long int biClrUsed, biClrImportant;
|
||||
};
|
||||
|
||||
struct _TGAHEADER
|
||||
{
|
||||
unsigned char tiIdentSize;
|
||||
unsigned char tiPaletteIncluded;
|
||||
unsigned char tiImageType;
|
||||
unsigned short tiPaletteStart;
|
||||
unsigned short tiPaletteSize;
|
||||
unsigned char tiPaletteBpp;
|
||||
unsigned short tiX0;
|
||||
unsigned short tiY0;
|
||||
unsigned short tiXres;
|
||||
unsigned short tiYres;
|
||||
unsigned char tiBitPerPixel;
|
||||
unsigned char tiAttrBits;
|
||||
};
|
||||
|
||||
public:
|
||||
int DLL Init( int Xres, int Yres, unsigned short BitPerPixel );
|
||||
int DLL SetImage(unsigned char *img, int width, int height, int bpp);
|
||||
int DLL Destroy();
|
||||
int DLL ConvertTo32( void );
|
||||
int DLL ConvertTo24( void );
|
||||
int DLL ConvertTo16( void );
|
||||
int DLL Convert8To17( int transindex );
|
||||
int DLL Convert32To17( void );
|
||||
int SaveBmp(char *szFilename);
|
||||
int LoadBmp(char *szFilename);
|
||||
int SaveTga(char *szFilename, bool bCompressed );
|
||||
int LoadTga(char *szFilename);
|
||||
int DLL Load(char *szFilename);
|
||||
int DLL Save(char *szFilename);
|
||||
|
||||
private:
|
||||
void Output( char * pcData, int nSize );
|
||||
void Output( char c );
|
||||
void Output( void );
|
||||
unsigned char Input( void );
|
||||
|
||||
public:
|
||||
int m_Xres, m_Yres;
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "i_system.h"
|
||||
#include "g_level.h"
|
||||
#include "c_console.h"
|
||||
|
@ -237,7 +239,7 @@ void CheckBench()
|
|||
AppendRenderTimes(compose);
|
||||
AppendLightStats(compose);
|
||||
AppendMissingTextureStats(compose);
|
||||
compose.AppendFormat("%d fps\n\n", screen->GetLastFPS());
|
||||
compose.AppendFormat("%" PRIu64 " fps\n\n", screen->GetLastFPS());
|
||||
|
||||
FILE *f = fopen("benchmarks.txt", "at");
|
||||
if (f != NULL)
|
||||
|
|
|
@ -55,26 +55,27 @@ static double TimeScale = 1.0;
|
|||
|
||||
CUSTOM_CVAR(Float, i_timescale, 1.0f, CVAR_NOINITCALL)
|
||||
{
|
||||
if (netgame && self != 1.0f)
|
||||
if (netgame)
|
||||
{
|
||||
Printf("Time scale cannot be changed in net games.\n");
|
||||
self = 1.0f;
|
||||
}
|
||||
else
|
||||
else if (self >= 0.05f)
|
||||
{
|
||||
I_FreezeTime(true);
|
||||
float clampValue = (self < 0.05) ? 0.05f : self;
|
||||
if (self != clampValue)
|
||||
self = clampValue;
|
||||
TimeScale = self;
|
||||
I_FreezeTime(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Time scale must be at least 0.05!\n");
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t GetClockTimeNS()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
return (uint64_t)((duration_cast<nanoseconds>(steady_clock::now().time_since_epoch()).count()) * TimeScale);
|
||||
return (uint64_t)((duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count()) * (uint64_t)(TimeScale * 1000));
|
||||
}
|
||||
|
||||
static uint64_t MSToNS(unsigned int ms)
|
||||
|
|
|
@ -88,86 +88,6 @@ EXTERN_CVAR(Bool, longsavemessages);
|
|||
|
||||
static long ParseCommandLine (const char *args, int *argc, char **argv);
|
||||
|
||||
//
|
||||
// M_WriteFile
|
||||
//
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
bool M_WriteFile (char const *name, void *source, int length)
|
||||
{
|
||||
int handle;
|
||||
int count;
|
||||
|
||||
handle = open ( name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
|
||||
|
||||
if (handle == -1)
|
||||
return false;
|
||||
|
||||
count = write (handle, source, length);
|
||||
close (handle);
|
||||
|
||||
if (count < length)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// M_ReadFile
|
||||
//
|
||||
int M_ReadFile (char const *name, uint8_t **buffer)
|
||||
{
|
||||
int handle, count, length;
|
||||
struct stat fileinfo;
|
||||
uint8_t *buf;
|
||||
|
||||
handle = open (name, O_RDONLY | O_BINARY, 0666);
|
||||
if (handle == -1)
|
||||
I_Error ("Couldn't read file %s", name);
|
||||
// [BL] Use stat instead of fstat for v140_xp hack
|
||||
if (stat (name,&fileinfo) == -1)
|
||||
I_Error ("Couldn't read file %s", name);
|
||||
length = fileinfo.st_size;
|
||||
buf = new uint8_t[length];
|
||||
count = read (handle, buf, length);
|
||||
close (handle);
|
||||
|
||||
if (count < length)
|
||||
I_Error ("Couldn't read file %s", name);
|
||||
|
||||
*buffer = buf;
|
||||
return length;
|
||||
}
|
||||
|
||||
//
|
||||
// M_ReadFile (same as above but use malloc instead of new to allocate the buffer.)
|
||||
//
|
||||
int M_ReadFileMalloc (char const *name, uint8_t **buffer)
|
||||
{
|
||||
int handle, count, length;
|
||||
struct stat fileinfo;
|
||||
uint8_t *buf;
|
||||
|
||||
handle = open (name, O_RDONLY | O_BINARY, 0666);
|
||||
if (handle == -1)
|
||||
I_Error ("Couldn't read file %s", name);
|
||||
// [BL] Use stat instead of fstat for v140_xp hack
|
||||
if (stat (name,&fileinfo) == -1)
|
||||
I_Error ("Couldn't read file %s", name);
|
||||
length = fileinfo.st_size;
|
||||
buf = (uint8_t*)M_Malloc(length);
|
||||
count = read (handle, buf, length);
|
||||
close (handle);
|
||||
|
||||
if (count < length)
|
||||
I_Error ("Couldn't read file %s", name);
|
||||
|
||||
*buffer = buf;
|
||||
return length;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
|
@ -192,7 +112,6 @@ void M_FindResponseFile (void)
|
|||
char **argv;
|
||||
char *file = NULL;
|
||||
int argc = 0;
|
||||
FILE *handle;
|
||||
int size;
|
||||
long argsize = 0;
|
||||
int index;
|
||||
|
@ -202,22 +121,18 @@ void M_FindResponseFile (void)
|
|||
if (added_stuff < limit)
|
||||
{
|
||||
// READ THE RESPONSE FILE INTO MEMORY
|
||||
handle = fopen (Args->GetArg(i) + 1,"rb");
|
||||
if (!handle)
|
||||
FileReader fr;
|
||||
if (!fr.Open(Args->GetArg(i) + 1))
|
||||
{ // [RH] Make this a warning, not an error.
|
||||
Printf ("No such response file (%s)!\n", Args->GetArg(i) + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("Found response file %s!\n", Args->GetArg(i) + 1);
|
||||
fseek (handle, 0, SEEK_END);
|
||||
size = ftell (handle);
|
||||
fseek (handle, 0, SEEK_SET);
|
||||
size = fr.GetLength();
|
||||
file = new char[size+1];
|
||||
fread (file, size, 1, handle);
|
||||
fr.Read (file, size);
|
||||
file[size] = 0;
|
||||
fclose (handle);
|
||||
|
||||
argsize = ParseCommandLine (file, &argc, NULL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,9 +33,6 @@ class FIWadManager;
|
|||
|
||||
extern FGameConfigFile *GameConfig;
|
||||
|
||||
bool M_WriteFile (char const *name, void *source, int length);
|
||||
int M_ReadFile (char const *name, uint8_t **buffer);
|
||||
int M_ReadFileMalloc (char const *name, uint8_t **buffer);
|
||||
void M_FindResponseFile (void);
|
||||
|
||||
// [RH] M_ScreenShot now accepts a filename parameter.
|
||||
|
@ -56,6 +53,7 @@ FString M_ZLibError(int zerrnum);
|
|||
#ifdef __unix__
|
||||
FString GetUserFile (const char *path); // Prepends ~/.zdoom to path
|
||||
#endif
|
||||
FString M_GetAppDataPath(bool create);
|
||||
FString M_GetCachePath(bool create);
|
||||
FString M_GetAutoexecPath();
|
||||
FString M_GetCajunPath(const char *filename);
|
||||
|
|
|
@ -383,18 +383,22 @@ PNGHandle *M_VerifyPNG (FileReader *filer, bool takereader)
|
|||
|
||||
if (filer->Read(&data, 8) != 8)
|
||||
{
|
||||
if (takereader) delete filer;
|
||||
return NULL;
|
||||
}
|
||||
if (data[0] != MAKE_ID(137,'P','N','G') || data[1] != MAKE_ID(13,10,26,10))
|
||||
{ // Does not have PNG signature
|
||||
if (takereader) delete filer;
|
||||
return NULL;
|
||||
}
|
||||
if (filer->Read (&data, 8) != 8)
|
||||
{
|
||||
if (takereader) delete filer;
|
||||
return NULL;
|
||||
}
|
||||
if (data[1] != MAKE_ID('I','H','D','R'))
|
||||
{ // IHDR must be the first chunk
|
||||
if (takereader) delete filer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -452,12 +456,6 @@ PNGHandle *M_VerifyPNG (FileReader *filer, bool takereader)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
PNGHandle *M_VerifyPNG(FILE *file)
|
||||
{
|
||||
FileReader *fr = new FileReader(file);
|
||||
return M_VerifyPNG(fr, true);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// M_FreePNG
|
||||
|
|
|
@ -90,7 +90,6 @@ struct PNGHandle
|
|||
// each chunk is not done. If it is valid, you get a PNGHandle to pass to
|
||||
// the following functions.
|
||||
PNGHandle *M_VerifyPNG (FileReader *file, bool takereader = false);
|
||||
PNGHandle *M_VerifyPNG (FILE *file);
|
||||
|
||||
// Finds a chunk in a PNG file. The file pointer will be positioned at the
|
||||
// beginning of the chunk data, and its length will be returned. A return
|
||||
|
|
|
@ -269,8 +269,8 @@ CCMD (md5sum)
|
|||
}
|
||||
for (int i = 1; i < argv.argc(); ++i)
|
||||
{
|
||||
FILE *file = fopen(argv[i], "rb");
|
||||
if (file == NULL)
|
||||
FileReader fr;
|
||||
if (!fr.Open(argv[i]))
|
||||
{
|
||||
Printf("%s: %s\n", argv[i], strerror(errno));
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ CCMD (md5sum)
|
|||
uint8_t readbuf[8192];
|
||||
size_t len;
|
||||
|
||||
while ((len = fread(readbuf, 1, sizeof(readbuf), file)) > 0)
|
||||
while ((len = fr.Read(readbuf, sizeof(readbuf))) > 0)
|
||||
{
|
||||
md5.Update(readbuf, (unsigned int)len);
|
||||
}
|
||||
|
@ -290,7 +290,6 @@ CCMD (md5sum)
|
|||
Printf("%02x", readbuf[j]);
|
||||
}
|
||||
Printf(" *%s\n", argv[i]);
|
||||
fclose (file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -236,8 +236,8 @@ void FSavegameManager::ReadSaveStrings()
|
|||
}
|
||||
else // check for old formats.
|
||||
{
|
||||
FILE *file = fopen(filepath, "rb");
|
||||
if (file != nullptr)
|
||||
FileReader file;
|
||||
if (file.Open(filepath))
|
||||
{
|
||||
PNGHandle *png;
|
||||
char sig[16];
|
||||
|
@ -255,8 +255,7 @@ void FSavegameManager::ReadSaveStrings()
|
|||
|
||||
title[OLDSAVESTRINGSIZE] = 0;
|
||||
|
||||
|
||||
if (nullptr != (png = M_VerifyPNG(file)))
|
||||
if (nullptr != (png = M_VerifyPNG(&file, false)))
|
||||
{
|
||||
char *ver = M_GetPNGText(png, "ZDoom Save Version");
|
||||
if (ver != nullptr)
|
||||
|
@ -273,13 +272,13 @@ void FSavegameManager::ReadSaveStrings()
|
|||
}
|
||||
else
|
||||
{
|
||||
fseek(file, 0, SEEK_SET);
|
||||
if (fread(sig, 1, 16, file) == 16)
|
||||
file.Seek(0, SEEK_SET);
|
||||
if (file.Read(sig, 16) == 16)
|
||||
{
|
||||
|
||||
if (strncmp(sig, "ZDOOMSAVE", 9) == 0)
|
||||
{
|
||||
if (fread(title, 1, OLDSAVESTRINGSIZE, file) == OLDSAVESTRINGSIZE)
|
||||
if (file.Read(title, OLDSAVESTRINGSIZE) == OLDSAVESTRINGSIZE)
|
||||
{
|
||||
addIt = true;
|
||||
}
|
||||
|
@ -287,8 +286,8 @@ void FSavegameManager::ReadSaveStrings()
|
|||
else
|
||||
{
|
||||
memcpy(title, sig, 16);
|
||||
if (fread(title + 16, 1, OLDSAVESTRINGSIZE - 16, file) == OLDSAVESTRINGSIZE - 16 &&
|
||||
fread(sig, 1, 16, file) == 16 &&
|
||||
if (file.Read(title + 16, OLDSAVESTRINGSIZE - 16) == OLDSAVESTRINGSIZE - 16 &&
|
||||
file.Read(sig, 16) == 16 &&
|
||||
strncmp(sig, "ZDOOMSAVE", 9) == 0)
|
||||
{
|
||||
addIt = true;
|
||||
|
@ -306,7 +305,6 @@ void FSavegameManager::ReadSaveStrings()
|
|||
node->SaveTitle = title;
|
||||
InsertSaveNode(node);
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
} while (I_FindNext(filefirst, &c_file) == 0);
|
||||
|
@ -418,17 +416,14 @@ void FSavegameManager::DoSave(int Selected, const char *savegamestring)
|
|||
// Find an unused filename and save as that
|
||||
FString filename;
|
||||
int i;
|
||||
FILE *test;
|
||||
|
||||
for (i = 0;; ++i)
|
||||
{
|
||||
filename = G_BuildSaveName("save", i);
|
||||
test = fopen(filename, "rb");
|
||||
if (test == nullptr)
|
||||
if (!FileExists(filename))
|
||||
{
|
||||
break;
|
||||
}
|
||||
fclose(test);
|
||||
}
|
||||
G_SaveGame(filename, savegamestring);
|
||||
}
|
||||
|
|
|
@ -1365,6 +1365,8 @@ void ACSStringPool::ReadStrings(FSerializer &file, const char *key)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
FindFirstFreeEntry(FirstFreeEntry);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
|
|
@ -1133,16 +1133,15 @@ static void CreateCachedNodes(MapData *map)
|
|||
memcpy(compressed + offset - 4, "ZGL3", 4);
|
||||
|
||||
FString path = CreateCacheName(map, true);
|
||||
FILE *f = fopen(path, "wb");
|
||||
FileWriter *fw = FileWriter::Open(path);
|
||||
|
||||
if (f != NULL)
|
||||
if (fw != nullptr)
|
||||
{
|
||||
if (fwrite(compressed, outlen+offset, 1, f) != 1)
|
||||
if (fw->Write(compressed, outlen+offset) != 1)
|
||||
{
|
||||
Printf("Error saving nodes to file %s\n", path.GetChars());
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
delete fw;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1162,32 +1161,30 @@ static bool CheckCachedNodes(MapData *map)
|
|||
uint32_t *verts = NULL;
|
||||
|
||||
FString path = CreateCacheName(map, false);
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (f == NULL) return false;
|
||||
FileReader fr;
|
||||
|
||||
if (fread(magic, 1, 4, f) != 4) goto errorout;
|
||||
if (!fr.Open(path)) return false;
|
||||
|
||||
if (fr.Read(magic, 4) != 4) goto errorout;
|
||||
if (memcmp(magic, "CACH", 4)) goto errorout;
|
||||
|
||||
if (fread(&numlin, 4, 1, f) != 1) goto errorout;
|
||||
if (fr.Read(&numlin, 4) != 4) goto errorout;
|
||||
numlin = LittleLong(numlin);
|
||||
if (numlin != level.lines.Size()) goto errorout;
|
||||
|
||||
if (fread(md5, 1, 16, f) != 16) goto errorout;
|
||||
if (fr.Read(md5, 16) != 16) goto errorout;
|
||||
map->GetChecksum(md5map);
|
||||
if (memcmp(md5, md5map, 16)) goto errorout;
|
||||
|
||||
verts = new uint32_t[numlin * 8];
|
||||
if (fread(verts, 8, numlin, f) != numlin) goto errorout;
|
||||
if (fr.Read(verts, 8 * numlin) != 8 * numlin) goto errorout;
|
||||
|
||||
if (fread(magic, 1, 4, f) != 4) goto errorout;
|
||||
if (fr.Read(magic, 4) != 4) goto errorout;
|
||||
if (memcmp(magic, "ZGL2", 4) && memcmp(magic, "ZGL3", 4)) goto errorout;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
long pos = ftell(f);
|
||||
FileReader fr(f);
|
||||
fr.Seek(pos, SEEK_SET);
|
||||
P_LoadZNodes (fr, MAKE_ID(magic[0],magic[1],magic[2],magic[3]));
|
||||
}
|
||||
catch (CRecoverableError &error)
|
||||
|
@ -1208,7 +1205,6 @@ static bool CheckCachedNodes(MapData *map)
|
|||
}
|
||||
delete [] verts;
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
|
||||
errorout:
|
||||
|
@ -1216,7 +1212,6 @@ errorout:
|
|||
{
|
||||
delete[] verts;
|
||||
}
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -126,6 +126,24 @@ void PolyDrawArgs::SetColor(uint32_t bgra, uint8_t palindex)
|
|||
}
|
||||
}
|
||||
|
||||
void PolyDrawArgs::DrawArray(const DrawerCommandQueuePtr &queue, const TriVertex *vertices, int vcount, PolyDrawMode mode)
|
||||
{
|
||||
mVertices = vertices;
|
||||
mVertexCount = vcount;
|
||||
mElements = nullptr;
|
||||
mDrawMode = mode;
|
||||
queue->Push<DrawPolyTrianglesCommand>(*this, PolyTriangleDrawer::is_mirror());
|
||||
}
|
||||
|
||||
void PolyDrawArgs::DrawElements(const DrawerCommandQueuePtr &queue, const TriVertex *vertices, const unsigned int *elements, int count, PolyDrawMode mode)
|
||||
{
|
||||
mVertices = vertices;
|
||||
mElements = elements;
|
||||
mVertexCount = count;
|
||||
mDrawMode = mode;
|
||||
queue->Push<DrawPolyTrianglesCommand>(*this, PolyTriangleDrawer::is_mirror());
|
||||
}
|
||||
|
||||
void PolyDrawArgs::DrawArray(PolyRenderThread *thread, const TriVertex *vertices, int vcount, PolyDrawMode mode)
|
||||
{
|
||||
mVertices = vertices;
|
||||
|
|
|
@ -84,6 +84,8 @@ public:
|
|||
void SetDynLightColor(uint32_t color) { mDynLightColor = color; }
|
||||
void DrawArray(PolyRenderThread *thread, const TriVertex *vertices, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles);
|
||||
void DrawElements(PolyRenderThread *thread, const TriVertex *vertices, const unsigned int *elements, int count, PolyDrawMode mode = PolyDrawMode::Triangles);
|
||||
void DrawArray(const DrawerCommandQueuePtr &queue, const TriVertex *vertices, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles);
|
||||
void DrawElements(const DrawerCommandQueuePtr &queue, const TriVertex *vertices, const unsigned int *elements, int count, PolyDrawMode mode = PolyDrawMode::Triangles);
|
||||
|
||||
const TriMatrix *ObjectToClip() const { return mObjectToClip; }
|
||||
const PolyClipPlane &ClipPlane(int index) const { return mClipPlane[index]; }
|
||||
|
|
|
@ -243,6 +243,15 @@ bool PolyTriangleDrawer::is_degenerate(const ShadedTriVertex *vert)
|
|||
return crosslengthsqr <= 1.e-6f;
|
||||
}
|
||||
|
||||
bool PolyTriangleDrawer::is_frontfacing(TriDrawTriangleArgs *args)
|
||||
{
|
||||
float a =
|
||||
args->v1->x * args->v2->y - args->v2->x * args->v1->y +
|
||||
args->v2->x * args->v3->y - args->v3->x * args->v2->y +
|
||||
args->v3->x * args->v1->y - args->v1->x * args->v3->y;
|
||||
return a <= 0.0f;
|
||||
}
|
||||
|
||||
void PolyTriangleDrawer::draw_shaded_triangle(const ShadedTriVertex *vert, bool ccw, TriDrawTriangleArgs *args, WorkerThreadData *thread)
|
||||
{
|
||||
// Reject triangle if degenerate
|
||||
|
@ -324,7 +333,7 @@ void PolyTriangleDrawer::draw_shaded_triangle(const ShadedTriVertex *vert, bool
|
|||
args->v1 = &clippedvert[numclipvert - 1];
|
||||
args->v2 = &clippedvert[i - 1];
|
||||
args->v3 = &clippedvert[i - 2];
|
||||
if (args->CalculateGradients())
|
||||
if (is_frontfacing(args) && args->CalculateGradients())
|
||||
ScreenTriangle::Draw(args, thread);
|
||||
}
|
||||
}
|
||||
|
@ -335,7 +344,7 @@ void PolyTriangleDrawer::draw_shaded_triangle(const ShadedTriVertex *vert, bool
|
|||
args->v1 = &clippedvert[0];
|
||||
args->v2 = &clippedvert[i - 1];
|
||||
args->v3 = &clippedvert[i];
|
||||
if (args->CalculateGradients())
|
||||
if (!is_frontfacing(args) && args->CalculateGradients())
|
||||
ScreenTriangle::Draw(args, thread);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ private:
|
|||
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);
|
||||
static bool is_frontfacing(TriDrawTriangleArgs *args);
|
||||
|
||||
static int clipedge(const ShadedTriVertex *verts, ShadedTriVertex *clippedvert);
|
||||
|
||||
|
|
|
@ -1071,16 +1071,21 @@ void TriangleBlock::DepthWrite(const TriDrawTriangleArgs *args)
|
|||
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
EXTERN_CVAR(Bool, r_polyrenderer)
|
||||
|
||||
void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thread)
|
||||
{
|
||||
TriangleBlock block(args, thread);
|
||||
block.Render();
|
||||
if (r_polyrenderer)
|
||||
{
|
||||
TriangleBlock block(args, thread);
|
||||
block.Render();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSWRender(args, thread);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void SortVertices(const TriDrawTriangleArgs *args, ShadedTriVertex **sortedVertices)
|
||||
{
|
||||
sortedVertices[0] = args->v1;
|
||||
|
@ -1095,7 +1100,7 @@ static void SortVertices(const TriDrawTriangleArgs *args, ShadedTriVertex **sort
|
|||
std::swap(sortedVertices[1], sortedVertices[2]);
|
||||
}
|
||||
|
||||
void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thread)
|
||||
void ScreenTriangle::DrawSWRender(const TriDrawTriangleArgs *args, WorkerThreadData *thread)
|
||||
{
|
||||
// Sort vertices by Y position
|
||||
ShadedTriVertex *sortedVertices[3];
|
||||
|
@ -1172,27 +1177,97 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thr
|
|||
}
|
||||
}
|
||||
|
||||
// Make variables local so the compiler can optimize without worrying about pointer aliasing
|
||||
// Draw the triangle:
|
||||
|
||||
bool depthTest = args->uniforms->DepthTest();
|
||||
bool writeColor = args->uniforms->WriteColor();
|
||||
bool writeStencil = args->uniforms->WriteStencil();
|
||||
bool writeDepth = args->uniforms->WriteDepth();
|
||||
auto drawfunc = (args->destBgra) ? DrawSpan32 : DrawSpan8;
|
||||
|
||||
uint8_t stencilTestValue = args->uniforms->StencilTestValue();
|
||||
uint8_t stencilWriteValue = args->uniforms->StencilWriteValue();
|
||||
float stepXW = args->gradientX.W;
|
||||
float v1X = args->v1->x;
|
||||
float v1Y = args->v1->y;
|
||||
float v1W = args->v1->w;
|
||||
|
||||
int bmode = (int)args->uniforms->BlendMode();
|
||||
auto drawFunc = args->destBgra ? ScreenTriangle::TriDrawers32[bmode] : ScreenTriangle::TriDrawers8[bmode];
|
||||
int num_cores = thread->num_cores;
|
||||
for (int y = topY + thread->skipped_by_thread(topY); y < bottomY; y += num_cores)
|
||||
{
|
||||
int x = leftEdge[y];
|
||||
int xend = rightEdge[y];
|
||||
|
||||
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 *zbufferLine = args->zbuffer + args->stencilPitch * 8 * y;
|
||||
|
||||
float startX = x + (0.5f - v1X);
|
||||
float startY = y + (0.5f - v1Y);
|
||||
float posXW = v1W + stepXW * startX + args->gradientY.W * startY;
|
||||
|
||||
#ifndef NO_SSE
|
||||
__m128 mstepXW = _mm_set1_ps(stepXW * 4.0f);
|
||||
__m128 mfirstStepXW = _mm_setr_ps(0.0f, stepXW, stepXW + stepXW, stepXW + stepXW + stepXW);
|
||||
while (x < xend)
|
||||
{
|
||||
int xstart = x;
|
||||
|
||||
int xendsse = x + ((xend - x) & ~3);
|
||||
__m128 mposXW = _mm_add_ps(_mm_set1_ps(posXW), mfirstStepXW);
|
||||
while (_mm_movemask_ps(_mm_cmple_ps(_mm_loadu_ps(zbufferLine + x), mposXW)) == 15 && x < xendsse)
|
||||
{
|
||||
_mm_storeu_ps(zbufferLine + x, mposXW);
|
||||
mposXW = _mm_add_ps(mposXW, mstepXW);
|
||||
x += 4;
|
||||
}
|
||||
posXW = _mm_cvtss_f32(mposXW);
|
||||
|
||||
while (zbufferLine[x] <= posXW && x < xend)
|
||||
{
|
||||
zbufferLine[x] = posXW;
|
||||
posXW += stepXW;
|
||||
x++;
|
||||
}
|
||||
|
||||
if (x > xstart)
|
||||
drawfunc(y, xstart, x, args);
|
||||
|
||||
xendsse = x + ((xend - x) & ~3);
|
||||
mposXW = _mm_add_ps(_mm_set1_ps(posXW), mfirstStepXW);
|
||||
while (_mm_movemask_ps(_mm_cmple_ps(_mm_loadu_ps(zbufferLine + x), mposXW)) == 0 && x < xendsse)
|
||||
{
|
||||
mposXW = _mm_add_ps(mposXW, mstepXW);
|
||||
x += 4;
|
||||
}
|
||||
posXW = _mm_cvtss_f32(mposXW);
|
||||
|
||||
while (zbufferLine[x] > posXW && x < xend)
|
||||
{
|
||||
posXW += stepXW;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
#else
|
||||
while (x < xend)
|
||||
{
|
||||
int xstart = x;
|
||||
while (zbufferLine[x] <= posXW && x < xend)
|
||||
{
|
||||
zbufferLine[x] = posXW;
|
||||
posXW += stepXW;
|
||||
x++;
|
||||
}
|
||||
|
||||
if (x > xstart)
|
||||
drawfunc(y, xstart, x, args);
|
||||
|
||||
while (zbufferLine[x] > posXW && x < xend)
|
||||
{
|
||||
posXW += stepXW;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NO_SSE
|
||||
|
||||
void ScreenTriangle::DrawSpan32(int y, int x0, int x1, const TriDrawTriangleArgs *args)
|
||||
{
|
||||
float v1X = args->v1->x;
|
||||
float v1Y = args->v1->y;
|
||||
float v1W = args->v1->w;
|
||||
|
@ -1201,13 +1276,15 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thr
|
|||
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;
|
||||
float startX = x0 + (0.5f - v1X);
|
||||
float startY = y + (0.5f - v1Y);
|
||||
float posXW = v1W + stepXW * startX + args->gradientY.W * startY;
|
||||
float posXU = v1U + stepXU * startX + args->gradientY.U * startY;
|
||||
float posXV = v1V + stepXV * startX + args->gradientY.V * startY;
|
||||
|
||||
const uint32_t *texPixels = (const uint32_t*)args->uniforms->TexturePixels();
|
||||
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;
|
||||
|
@ -1216,86 +1293,225 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thr
|
|||
float globVis = args->uniforms->GlobVis() * (1.0f / 32.0f);
|
||||
light += light >> 7; // 255 -> 256
|
||||
|
||||
// Draw the triangle:
|
||||
uint32_t *dest = (uint32_t*)args->dest;
|
||||
uint32_t *destLine = dest + args->pitch * y;
|
||||
|
||||
int num_cores = thread->num_cores;
|
||||
for (int y = topY + thread->skipped_by_thread(topY); y < bottomY; y += num_cores)
|
||||
int x = x0;
|
||||
int sseEnd = x0 + ((x1 - x0) & ~3);
|
||||
while (x < sseEnd)
|
||||
{
|
||||
int x0 = leftEdge[y];
|
||||
int x1 = rightEdge[y];
|
||||
uint32_t fgcolor[2];
|
||||
int32_t lightshade[2];
|
||||
|
||||
uint8_t *destLine = dest + pitch * y;
|
||||
uint8_t *stencilLine = stencilbuffer + stencilpitch * y;
|
||||
float *zbufferLine = zbuffer + stencilpitch * y;
|
||||
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;
|
||||
fgcolor[0] = texPixels[texelX * texHeight + texelY];
|
||||
|
||||
if ((stencilMasks[y] & 0xffffff00) == 0xffffff00) // First time we draw a line we have to clear the stencil buffer
|
||||
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);
|
||||
lightshade[0] = lightpos >> 8;
|
||||
|
||||
posXW += stepXW;
|
||||
posXU += stepXU;
|
||||
posXV += stepXV;
|
||||
|
||||
rcpW = 0x01000000 / posXW;
|
||||
u = (int32_t)(posXU * rcpW);
|
||||
v = (int32_t)(posXV * rcpW);
|
||||
texelX = ((((uint32_t)u << 8) >> 16) * texWidth) >> 16;
|
||||
texelY = ((((uint32_t)v << 8) >> 16) * texHeight) >> 16;
|
||||
fgcolor[1] = texPixels[texelX * texHeight + texelY];
|
||||
|
||||
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);
|
||||
lightshade[1] = lightpos >> 8;
|
||||
|
||||
posXW += stepXW;
|
||||
posXU += stepXU;
|
||||
posXV += stepXV;
|
||||
|
||||
__m128i mfgcolor = _mm_loadl_epi64((const __m128i*)fgcolor);
|
||||
mfgcolor = _mm_unpacklo_epi8(mfgcolor, _mm_setzero_si128());
|
||||
|
||||
__m128i mlightshade = _mm_loadl_epi64((const __m128i*)lightshade);
|
||||
mlightshade = _mm_shuffle_epi32(mlightshade, _MM_SHUFFLE(1, 0, 1, 0));
|
||||
mlightshade = _mm_packs_epi32(mlightshade, mlightshade);
|
||||
|
||||
__m128i mdestcolor = _mm_srli_epi16(_mm_mullo_epi16(mfgcolor, mlightshade), 8);
|
||||
mdestcolor = _mm_packus_epi16(mdestcolor, _mm_setzero_si128());
|
||||
mdestcolor = _mm_or_si128(mdestcolor, _mm_set1_epi32(0xff000000));
|
||||
|
||||
_mm_storel_epi64((__m128i*)(destLine + x), mdestcolor);
|
||||
|
||||
x += 2;
|
||||
}
|
||||
|
||||
while (x < x1)
|
||||
{
|
||||
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;
|
||||
uint32_t fgcolor = texPixels[texelX * texHeight + texelY];
|
||||
|
||||
uint32_t fgcolor_r = RPART(fgcolor);
|
||||
uint32_t fgcolor_g = GPART(fgcolor);
|
||||
uint32_t fgcolor_b = BPART(fgcolor);
|
||||
uint32_t fgcolor_a = APART(fgcolor);
|
||||
if (fgcolor_a > 127)
|
||||
{
|
||||
memset(stencilLine, stencilMasks[y] & 0xff, stencilpitch);
|
||||
stencilMasks[y] = 0;
|
||||
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;
|
||||
|
||||
fgcolor_r = (fgcolor_r * lightshade) >> 8;
|
||||
fgcolor_g = (fgcolor_g * lightshade) >> 8;
|
||||
fgcolor_b = (fgcolor_b * lightshade) >> 8;
|
||||
|
||||
destLine[x] = 0xff000000 | (fgcolor_r << 16) | (fgcolor_g << 8) | fgcolor_b;
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
posXW += stepXW;
|
||||
posXU += stepXU;
|
||||
posXV += stepXV;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void ScreenTriangle::DrawSpan32(int y, int x0, int x1, const TriDrawTriangleArgs *args)
|
||||
{
|
||||
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 startX = x0 + (0.5f - v1X);
|
||||
float startY = y + (0.5f - v1Y);
|
||||
float posXW = v1W + stepXW * startX + args->gradientY.W * startY;
|
||||
float posXU = v1U + stepXU * startX + args->gradientY.U * startY;
|
||||
float posXV = v1V + stepXV * startX + args->gradientY.V * startY;
|
||||
|
||||
const uint32_t *texPixels = (const uint32_t*)args->uniforms->TexturePixels();
|
||||
int texWidth = args->uniforms->TextureWidth();
|
||||
int texHeight = args->uniforms->TextureHeight();
|
||||
|
||||
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
|
||||
|
||||
uint32_t *dest = (uint32_t*)args->dest;
|
||||
uint32_t *destLine = dest + args->pitch * y;
|
||||
|
||||
int x = x0;
|
||||
while (x < x1)
|
||||
{
|
||||
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;
|
||||
uint32_t fgcolor = texPixels[texelX * texHeight + texelY];
|
||||
|
||||
uint32_t fgcolor_r = RPART(fgcolor);
|
||||
uint32_t fgcolor_g = GPART(fgcolor);
|
||||
uint32_t fgcolor_b = BPART(fgcolor);
|
||||
uint32_t fgcolor_a = APART(fgcolor);
|
||||
if (fgcolor_a > 127)
|
||||
{
|
||||
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;
|
||||
|
||||
fgcolor_r = (fgcolor_r * lightshade) >> 8;
|
||||
fgcolor_g = (fgcolor_g * lightshade) >> 8;
|
||||
fgcolor_b = (fgcolor_b * lightshade) >> 8;
|
||||
|
||||
destLine[x] = 0xff000000 | (fgcolor_r << 16) | (fgcolor_g << 8) | fgcolor_b;
|
||||
}
|
||||
|
||||
posXW += stepXW;
|
||||
posXU += stepXU;
|
||||
posXV += stepXV;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void ScreenTriangle::DrawSpan8(int y, int x0, int x1, const TriDrawTriangleArgs *args)
|
||||
{
|
||||
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 startX = x0 + (0.5f - v1X);
|
||||
float startY = y + (0.5f - v1Y);
|
||||
float posXW = v1W + stepXW * startX + args->gradientY.W * startY;
|
||||
float posXU = v1U + stepXU * startX + args->gradientY.U * startY;
|
||||
float posXV = v1V + stepXV * startX + args->gradientY.V * startY;
|
||||
|
||||
auto colormaps = args->uniforms->BaseColormap();
|
||||
|
||||
const uint8_t *texPixels = args->uniforms->TexturePixels();
|
||||
int texWidth = args->uniforms->TextureWidth();
|
||||
int texHeight = args->uniforms->TextureHeight();
|
||||
|
||||
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
|
||||
|
||||
uint8_t *dest = (uint8_t*)args->dest;
|
||||
uint8_t *destLine = dest + args->pitch * y;
|
||||
|
||||
int x = x0;
|
||||
while (x < x1)
|
||||
{
|
||||
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;
|
||||
|
||||
posXW += stepXW;
|
||||
posXU += stepXU;
|
||||
posXV += stepXV;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
void(*ScreenTriangle::TriDrawers8[])(int, int, uint32_t, uint32_t, const TriDrawTriangleArgs *) =
|
||||
{
|
||||
&TriScreenDrawer8<TriScreenDrawerModes::OpaqueBlend, TriScreenDrawerModes::TextureSampler>::Execute, // TextureOpaque
|
||||
|
|
|
@ -149,6 +149,9 @@ class ScreenTriangle
|
|||
{
|
||||
public:
|
||||
static void Draw(const TriDrawTriangleArgs *args, WorkerThreadData *thread);
|
||||
static void DrawSWRender(const TriDrawTriangleArgs *args, WorkerThreadData *thread);
|
||||
static void DrawSpan8(int y, int x0, int x1, const TriDrawTriangleArgs *args);
|
||||
static void DrawSpan32(int y, int x0, int x1, const TriDrawTriangleArgs *args);
|
||||
|
||||
static void(*TriDrawers8[])(int, int, uint32_t, uint32_t, const TriDrawTriangleArgs *);
|
||||
static void(*TriDrawers32[])(int, int, uint32_t, uint32_t, const TriDrawTriangleArgs *);
|
||||
|
|
|
@ -132,7 +132,6 @@ TriMatrix TriMatrix::frustum(float left, float right, float bottom, float top, f
|
|||
return m;
|
||||
}
|
||||
|
||||
#if 0
|
||||
TriMatrix TriMatrix::worldToView(const FRenderViewpoint &viewpoint)
|
||||
{
|
||||
TriMatrix m = null();
|
||||
|
@ -145,16 +144,15 @@ TriMatrix TriMatrix::worldToView(const FRenderViewpoint &viewpoint)
|
|||
return m * translate((float)-viewpoint.Pos.X, (float)-viewpoint.Pos.Y, (float)-viewpoint.Pos.Z);
|
||||
}
|
||||
|
||||
TriMatrix TriMatrix::viewToClip(double focalTangent, double centerY, double invZtoScale)
|
||||
TriMatrix TriMatrix::viewToClip(double focalTangent, double centerY, double YaspectMul)
|
||||
{
|
||||
float near = 5.0f;
|
||||
float far = 65536.0f;
|
||||
float width = (float)(focalTangent * near);
|
||||
float top = (float)(centerY / invZtoScale * near);
|
||||
float bottom = (float)(top - viewheight / invZtoScale * near);
|
||||
float top = (float)(centerY / viewheight * YaspectMul * near);
|
||||
float bottom = (float)(top - YaspectMul * near);
|
||||
return frustum(-width, width, bottom, top, near, far);
|
||||
}
|
||||
#endif
|
||||
|
||||
TriMatrix TriMatrix::operator*(const TriMatrix &mult) const
|
||||
{
|
||||
|
|
|
@ -36,8 +36,8 @@ struct TriMatrix
|
|||
static TriMatrix perspective(float fovy, float aspect, float near, float far);
|
||||
static TriMatrix frustum(float left, float right, float bottom, float top, float near, float far);
|
||||
|
||||
//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
|
||||
static TriMatrix worldToView(const FRenderViewpoint &viewpoint); // Software renderer world to view space transform
|
||||
static TriMatrix viewToClip(double focalTangent, double centerY, double YaspectMul); // Software renderer shearing projection
|
||||
|
||||
FVector4 operator*(const FVector4 &v) const;
|
||||
TriMatrix operator*(const TriMatrix &m) const;
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
#include "actorinlines.h"
|
||||
#include "i_time.h"
|
||||
|
||||
void gl_FlushModels();
|
||||
bool polymodelsInUse;
|
||||
|
||||
void PolyRenderModel(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor)
|
||||
{
|
||||
PolyModelRenderer renderer(thread, worldToClip, clipPlane, stencilValue);
|
||||
|
@ -47,6 +50,15 @@ void PolyRenderHUDModel(PolyRenderThread *thread, const TriMatrix &worldToClip,
|
|||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyModelRenderer::PolyModelRenderer(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue) : Thread(thread), WorldToClip(worldToClip), ClipPlane(clipPlane), StencilValue(stencilValue)
|
||||
{
|
||||
if (!polymodelsInUse)
|
||||
{
|
||||
gl_FlushModels();
|
||||
polymodelsInUse = true;
|
||||
}
|
||||
}
|
||||
|
||||
void PolyModelRenderer::BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix)
|
||||
{
|
||||
ModelActor = actor;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include "r_data/matrix.h"
|
||||
#include "gl/models/gl_models.h"
|
||||
#include "r_data/models/models.h"
|
||||
|
||||
void PolyRenderModel(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor);
|
||||
void PolyRenderHUDModel(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue, DPSprite *psp, float ofsx, float ofsy);
|
||||
|
@ -32,7 +32,7 @@ void PolyRenderHUDModel(PolyRenderThread *thread, const TriMatrix &worldToClip,
|
|||
class PolyModelRenderer : public FModelRenderer
|
||||
{
|
||||
public:
|
||||
PolyModelRenderer(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue) : Thread(thread), WorldToClip(worldToClip), ClipPlane(clipPlane), StencilValue(stencilValue) { }
|
||||
PolyModelRenderer(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, uint32_t stencilValue);
|
||||
|
||||
void BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix) override;
|
||||
void EndDrawModel(AActor *actor, FSpriteModelFrame *smf) override;
|
||||
|
|
|
@ -43,7 +43,7 @@ void RenderPolyPlayerSprites::Render(PolyRenderThread *thread)
|
|||
//
|
||||
// We also can't move it because the model render code relies on it
|
||||
|
||||
renderHUDModel = gl_IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player);
|
||||
//renderHUDModel = gl_IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player);
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ bool RenderPolySprite::GetLine(AActor *thing, DVector2 &left, DVector2 &right)
|
|||
|
||||
void RenderPolySprite::Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, AActor *thing, subsector_t *sub, uint32_t stencilValue, float t1, float t2)
|
||||
{
|
||||
int spritenum = thing->sprite;
|
||||
/*int spritenum = thing->sprite;
|
||||
bool isPicnumOverride = thing->picnum.isValid();
|
||||
FSpriteModelFrame *modelframe = isPicnumOverride ? nullptr : gl_FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED));
|
||||
if (modelframe)
|
||||
|
@ -83,7 +83,7 @@ void RenderPolySprite::Render(PolyRenderThread *thread, const TriMatrix &worldTo
|
|||
DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac);
|
||||
PolyRenderModel(thread, worldToClip, clipPlane, stencilValue, (float)pos.X, (float)pos.Y, (float)pos.Z, modelframe, thing);
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
|
||||
DVector2 line[2];
|
||||
if (!GetLine(thing, line[0], line[1]))
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "st_console.h"
|
||||
#include "v_text.h"
|
||||
#include "x86.h"
|
||||
#include "cmdlib.h"
|
||||
|
||||
|
||||
EXTERN_CVAR(String, language)
|
||||
|
@ -336,11 +337,11 @@ int I_FindClose(void* const handle)
|
|||
int I_FindAttr(findstate_t* const fileinfo)
|
||||
{
|
||||
dirent* const ent = fileinfo->namelist[fileinfo->current];
|
||||
struct stat buf;
|
||||
bool isdir;
|
||||
|
||||
if (stat(ent->d_name, &buf) == 0)
|
||||
if (DirEntryExists(ent->d_name, &isdir))
|
||||
{
|
||||
return S_ISDIR(buf.st_mode) ? FA_DIREC : 0;
|
||||
return isdir ? FA_DIREC : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "d_main.h"
|
||||
#include "zstring.h"
|
||||
#include "sc_man.h"
|
||||
#include "cmdlib.h"
|
||||
|
||||
static void PSR_FindEndBlock(FScanner &sc)
|
||||
{
|
||||
|
@ -122,27 +123,28 @@ static TArray<FString> ParseSteamRegistry(const char* path)
|
|||
|
||||
// Read registry data
|
||||
FScanner sc;
|
||||
sc.OpenFile(path);
|
||||
sc.SetCMode(true);
|
||||
|
||||
// Find the SteamApps listing
|
||||
if(PSR_FindAndEnterBlock(sc, "InstallConfigStore"))
|
||||
if (sc.OpenFile(path))
|
||||
{
|
||||
if(PSR_FindAndEnterBlock(sc, "Software"))
|
||||
sc.SetCMode(true);
|
||||
|
||||
// Find the SteamApps listing
|
||||
if (PSR_FindAndEnterBlock(sc, "InstallConfigStore"))
|
||||
{
|
||||
if(PSR_FindAndEnterBlock(sc, "Valve"))
|
||||
if (PSR_FindAndEnterBlock(sc, "Software"))
|
||||
{
|
||||
if(PSR_FindAndEnterBlock(sc, "Steam"))
|
||||
if (PSR_FindAndEnterBlock(sc, "Valve"))
|
||||
{
|
||||
dirs = PSR_ReadBaseInstalls(sc);
|
||||
if (PSR_FindAndEnterBlock(sc, "Steam"))
|
||||
{
|
||||
dirs = PSR_ReadBaseInstalls(sc);
|
||||
}
|
||||
PSR_FindEndBlock(sc);
|
||||
}
|
||||
PSR_FindEndBlock(sc);
|
||||
}
|
||||
PSR_FindEndBlock(sc);
|
||||
}
|
||||
PSR_FindEndBlock(sc);
|
||||
}
|
||||
|
||||
return dirs;
|
||||
}
|
||||
|
||||
|
@ -223,7 +225,7 @@ TArray<FString> I_GetSteamPath()
|
|||
{
|
||||
struct stat st;
|
||||
FString candidate(SteamInstallFolders[i] + "/" + AppInfo[app].BasePath);
|
||||
if(stat(candidate, &st) == 0 && S_ISDIR(st.st_mode))
|
||||
if(DirExists(candidate))
|
||||
result.Push(candidate);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,35 @@
|
|||
#include "m_misc.h"
|
||||
#include "version.h" // for GAMENAME
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetAppDataPath macOS
|
||||
//
|
||||
// Returns the path for the AppData folder.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetAppDataPath(bool create)
|
||||
{
|
||||
FString path;
|
||||
|
||||
char pathstr[PATH_MAX];
|
||||
FSRef folder;
|
||||
|
||||
if (noErr == FSFindFolder(kUserDomain, kApplicationSupportFolderType, create ? kCreateFolder : 0, &folder) &&
|
||||
noErr == FSRefMakePath(&folder, (UInt8*)pathstr, PATH_MAX))
|
||||
{
|
||||
path = pathstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
path = progdir;
|
||||
}
|
||||
path += "/" GAMENAMELOWERCASE;
|
||||
if (create) CreatePath(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetCachePath macOS
|
||||
|
@ -64,6 +93,7 @@ FString M_GetCachePath(bool create)
|
|||
path = progdir;
|
||||
}
|
||||
path += "/zdoom/cache";
|
||||
if (create) CreatePath(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
|
|
|
@ -397,15 +397,16 @@ int I_FindClose (void *handle)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int I_FindAttr (findstate_t *fileinfo)
|
||||
int I_FindAttr(findstate_t* const fileinfo)
|
||||
{
|
||||
dirent *ent = fileinfo->namelist[fileinfo->current];
|
||||
struct stat buf;
|
||||
dirent* const ent = fileinfo->namelist[fileinfo->current];
|
||||
bool isdir;
|
||||
|
||||
if (stat(ent->d_name, &buf) == 0)
|
||||
if (DirEntryExists(ent->d_name, &isdir))
|
||||
{
|
||||
return S_ISDIR(buf.st_mode) ? FA_DIREC : 0;
|
||||
return isdir ? FA_DIREC : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -98,6 +98,26 @@ FString GetUserFile (const char *file)
|
|||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetAppDataPath Unix
|
||||
//
|
||||
// Returns the path for the AppData folder.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetAppDataPath(bool create)
|
||||
{
|
||||
// Don't use GAME_DIR and such so that ZDoom and its child ports can
|
||||
// share the node cache.
|
||||
FString path = NicePath("~/.config/" GAMENAMELOWERCASE);
|
||||
if (create)
|
||||
{
|
||||
CreatePath(path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetCachePath Unix
|
||||
|
|
|
@ -209,10 +209,7 @@ int FDirectory::AddDirectory(const char *dirpath)
|
|||
|
||||
FString fullFileName = scanDirectories[i] + file->d_name;
|
||||
|
||||
struct stat fileStat;
|
||||
stat(fullFileName.GetChars(), &fileStat);
|
||||
|
||||
if(S_ISDIR(fileStat.st_mode))
|
||||
if(DirExists(fullFileName.GetChars()))
|
||||
{
|
||||
scanDirectories.Push(scanDirectories[i] + file->d_name + "/");
|
||||
continue;
|
||||
|
|
|
@ -542,7 +542,7 @@ static void time_to_dos(struct tm *time, unsigned short *dosdate, unsigned short
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int AppendToZip(FILE *zip_file, const char *filename, FCompressedBuffer &content, uint16_t date, uint16_t time)
|
||||
int AppendToZip(FileWriter *zip_file, const char *filename, FCompressedBuffer &content, uint16_t date, uint16_t time)
|
||||
{
|
||||
FZipLocalFileHeader local;
|
||||
int position;
|
||||
|
@ -562,12 +562,12 @@ int AppendToZip(FILE *zip_file, const char *filename, FCompressedBuffer &content
|
|||
|
||||
// Fill in local directory header.
|
||||
|
||||
position = (int)ftell(zip_file);
|
||||
position = (int)zip_file->Tell();
|
||||
|
||||
// Write out the header, file name, and file data.
|
||||
if (fwrite(&local, sizeof(local), 1, zip_file) != 1 ||
|
||||
fwrite(filename, strlen(filename), 1, zip_file) != 1 ||
|
||||
fwrite(content.mBuffer, 1, content.mCompressedSize, zip_file) != content.mCompressedSize)
|
||||
if (zip_file->Write(&local, sizeof(local)) != sizeof(local) ||
|
||||
zip_file->Write(filename, strlen(filename)) != strlen(filename) ||
|
||||
zip_file->Write(content.mBuffer, content.mCompressedSize) != content.mCompressedSize)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
@ -583,7 +583,7 @@ int AppendToZip(FILE *zip_file, const char *filename, FCompressedBuffer &content
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int AppendCentralDirectory(FILE *zip_file, const char *filename, FCompressedBuffer &content, uint16_t date, uint16_t time, int position)
|
||||
int AppendCentralDirectory(FileWriter *zip_file, const char *filename, FCompressedBuffer &content, uint16_t date, uint16_t time, int position)
|
||||
{
|
||||
FZipCentralDirectoryInfo dir;
|
||||
|
||||
|
@ -607,8 +607,8 @@ int AppendCentralDirectory(FILE *zip_file, const char *filename, FCompressedBuff
|
|||
dir.ExternalAttributes = 0;
|
||||
dir.LocalHeaderOffset = LittleLong(position);
|
||||
|
||||
if (fwrite(&dir, sizeof(dir), 1, zip_file) != 1 ||
|
||||
fwrite(filename, strlen(filename), 1, zip_file) != 1)
|
||||
if (zip_file->Write(&dir, sizeof(dir)) != sizeof(dir) ||
|
||||
zip_file->Write(filename, strlen(filename)) != strlen(filename))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
@ -629,7 +629,7 @@ bool WriteZip(const char *filename, TArray<FString> &filenames, TArray<FCompress
|
|||
|
||||
if (filenames.Size() != content.Size()) return false;
|
||||
|
||||
FILE *f = fopen(filename, "wb");
|
||||
auto f = FileWriter::Open(filename);
|
||||
if (f != nullptr)
|
||||
{
|
||||
for (unsigned i = 0; i < filenames.Size(); i++)
|
||||
|
@ -637,19 +637,19 @@ bool WriteZip(const char *filename, TArray<FString> &filenames, TArray<FCompress
|
|||
int pos = AppendToZip(f, filenames[i], content[i], mydate, mytime);
|
||||
if (pos == -1)
|
||||
{
|
||||
fclose(f);
|
||||
delete f;
|
||||
remove(filename);
|
||||
return false;
|
||||
}
|
||||
positions.Push(pos);
|
||||
}
|
||||
|
||||
int dirofs = (int)ftell(f);
|
||||
int dirofs = (int)f->Tell();
|
||||
for (unsigned i = 0; i < filenames.Size(); i++)
|
||||
{
|
||||
if (AppendCentralDirectory(f, filenames[i], content[i], mydate, mytime, positions[i]) < 0)
|
||||
{
|
||||
fclose(f);
|
||||
delete f;
|
||||
remove(filename);
|
||||
return false;
|
||||
}
|
||||
|
@ -662,15 +662,15 @@ bool WriteZip(const char *filename, TArray<FString> &filenames, TArray<FCompress
|
|||
dirend.FirstDisk = 0;
|
||||
dirend.NumEntriesOnAllDisks = dirend.NumEntries = LittleShort(filenames.Size());
|
||||
dirend.DirectoryOffset = LittleLong(dirofs);
|
||||
dirend.DirectorySize = LittleLong(ftell(f) - dirofs);
|
||||
dirend.DirectorySize = LittleLong(f->Tell() - dirofs);
|
||||
dirend.ZipCommentLength = 0;
|
||||
if (fwrite(&dirend, sizeof(dirend), 1, f) != 1)
|
||||
if (f->Write(&dirend, sizeof(dirend)) != sizeof(dirend))
|
||||
{
|
||||
fclose(f);
|
||||
delete f;
|
||||
remove(filename);
|
||||
return false;
|
||||
}
|
||||
fclose(f);
|
||||
delete f;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -669,12 +669,11 @@ FExternalLump::FExternalLump(const char *_filename, int filesize)
|
|||
|
||||
if (filesize == -1)
|
||||
{
|
||||
FILE *f = fopen(_filename,"rb");
|
||||
if (f != NULL)
|
||||
FileReader f;
|
||||
|
||||
if (f.Open(_filename))
|
||||
{
|
||||
fseek(f, 0, SEEK_END);
|
||||
LumpSize = ftell(f);
|
||||
fclose(f);
|
||||
LumpSize = f.GetLength();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -703,11 +702,11 @@ FExternalLump::~FExternalLump()
|
|||
int FExternalLump::FillCache()
|
||||
{
|
||||
Cache = new char[LumpSize];
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if (f != NULL)
|
||||
FileReader f;
|
||||
|
||||
if (f.Open(filename))
|
||||
{
|
||||
fread(Cache, 1, LumpSize, f);
|
||||
fclose(f);
|
||||
f.Read(Cache, LumpSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "s_playlist.h"
|
||||
#include "templates.h"
|
||||
#include "v_text.h"
|
||||
#include "files.h"
|
||||
|
||||
FPlayList::FPlayList (const char *path)
|
||||
{
|
||||
|
@ -53,7 +54,7 @@ bool FPlayList::ChangeList (const char *path)
|
|||
{
|
||||
FString playlistdir;
|
||||
FString song;
|
||||
FILE *file;
|
||||
FileReader fr;
|
||||
bool first;
|
||||
bool pls;
|
||||
int i;
|
||||
|
@ -61,7 +62,7 @@ bool FPlayList::ChangeList (const char *path)
|
|||
Songs.Clear();
|
||||
Position = 0;
|
||||
|
||||
if ( (file = fopen (path, "rb")) == NULL)
|
||||
if (!fr.Open(path))
|
||||
{
|
||||
Printf ("Could not open " TEXTCOLOR_BOLD "%s" TEXTCOLOR_NORMAL ": %s\n", path, strerror(errno));
|
||||
return false;
|
||||
|
@ -70,7 +71,7 @@ bool FPlayList::ChangeList (const char *path)
|
|||
first = true;
|
||||
pls = false;
|
||||
playlistdir = ExtractFilePath(path);
|
||||
while ((song = NextLine(file)).IsNotEmpty())
|
||||
while ((song = NextLine(&fr)).IsNotEmpty())
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
|
@ -129,19 +130,17 @@ bool FPlayList::ChangeList (const char *path)
|
|||
Songs.Push(song);
|
||||
}
|
||||
}
|
||||
fclose (file);
|
||||
|
||||
return Songs.Size() != 0;
|
||||
}
|
||||
|
||||
FString FPlayList::NextLine (FILE *file)
|
||||
FString FPlayList::NextLine (FileReader *file)
|
||||
{
|
||||
char buffer[512];
|
||||
char *skipper;
|
||||
|
||||
do
|
||||
{
|
||||
if (NULL == fgets (buffer, countof(buffer), file))
|
||||
if (NULL == file->Gets (buffer, countof(buffer)))
|
||||
return "";
|
||||
|
||||
for (skipper = buffer; *skipper != 0 && *skipper <= ' '; skipper++)
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#ifndef __S_PLAYLIST_H__
|
||||
#define __S_PLAYLIST_H__
|
||||
|
||||
class FileReader;
|
||||
|
||||
class FPlayList
|
||||
{
|
||||
public:
|
||||
|
@ -51,7 +53,7 @@ public:
|
|||
const char *GetSong (int position) const;
|
||||
|
||||
private:
|
||||
static FString NextLine (FILE *file);
|
||||
static FString NextLine (FileReader *file);
|
||||
|
||||
unsigned int Position;
|
||||
TArray<FString> Songs;
|
||||
|
|
|
@ -244,18 +244,25 @@ void FScanner::Open (const char *name)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void FScanner::OpenFile (const char *name)
|
||||
bool FScanner::OpenFile (const char *name)
|
||||
{
|
||||
uint8_t *filebuf;
|
||||
int filesize;
|
||||
|
||||
Close ();
|
||||
filesize = M_ReadFile (name, &filebuf);
|
||||
|
||||
FileReader fr(name);
|
||||
if (!fr.Open(name)) return false;
|
||||
auto filesize = fr.GetLength();
|
||||
auto filebuf = new uint8_t[filesize];
|
||||
if (fr.Read(filebuf, filesize) != filesize)
|
||||
{
|
||||
delete[] filebuf;
|
||||
return false;
|
||||
}
|
||||
ScriptBuffer = FString((const char *)filebuf, filesize);
|
||||
delete[] filebuf;
|
||||
ScriptName = name; // This is used for error messages so the full file name is preferable
|
||||
LumpNum = -1;
|
||||
PrepareScript ();
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -19,7 +19,7 @@ public:
|
|||
FScanner &operator=(const FScanner &other);
|
||||
|
||||
void Open(const char *lumpname);
|
||||
void OpenFile(const char *filename);
|
||||
bool OpenFile(const char *filename);
|
||||
void OpenMem(const char *name, const char *buffer, int size);
|
||||
void OpenString(const char *name, FString buffer);
|
||||
void OpenLumpNum(int lump);
|
||||
|
|
|
@ -462,11 +462,11 @@ static void DoParse(int lumpnum)
|
|||
FString filename = Wads.GetLumpFullPath(lumpnum);
|
||||
filename.ReplaceChars(":\\/?|", '.');
|
||||
filename << ".ast";
|
||||
FILE *ff = fopen(filename, "w");
|
||||
FileWriter *ff = FileWriter::Open(filename);
|
||||
if (ff != NULL)
|
||||
{
|
||||
fputs(ast.GetChars(), ff);
|
||||
fclose(ff);
|
||||
ff->Write(ast.GetChars(), ast.Len());
|
||||
delete ff;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -803,18 +803,17 @@ CCMD (writemidi)
|
|||
}
|
||||
|
||||
TArray<uint8_t> midi;
|
||||
FILE *f;
|
||||
bool success;
|
||||
|
||||
static_cast<MIDIStreamer *>(currSong)->CreateSMF(midi, 1);
|
||||
f = fopen(argv[1], "wb");
|
||||
auto f = FileWriter::Open(argv[1]);
|
||||
if (f == NULL)
|
||||
{
|
||||
Printf("Could not open %s.\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
success = (fwrite(&midi[0], 1, midi.Size(), f) == (size_t)midi.Size());
|
||||
fclose (f);
|
||||
success = (f->Write(&midi[0], midi.Size()) == (size_t)midi.Size());
|
||||
delete f;
|
||||
|
||||
if (!success)
|
||||
{
|
||||
|
|
|
@ -239,7 +239,7 @@ public:
|
|||
void Stop();
|
||||
|
||||
protected:
|
||||
FILE *File;
|
||||
FileWriter *File;
|
||||
};
|
||||
|
||||
// WildMidi implementation of a MIDI device ---------------------------------
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "m_swap.h"
|
||||
#include "w_wad.h"
|
||||
#include "opl.h"
|
||||
#include "files.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -48,7 +49,7 @@
|
|||
class OPLDump : public OPLEmul
|
||||
{
|
||||
public:
|
||||
OPLDump(FILE *file) : File(file), TimePerTick(0), CurTime(0),
|
||||
OPLDump(FileWriter *file) : File(file), TimePerTick(0), CurTime(0),
|
||||
CurIntTime(0), TickMul(1), CurChip(0) {}
|
||||
|
||||
// If we're doing things right, these should never be reset.
|
||||
|
@ -66,7 +67,7 @@ public:
|
|||
virtual void WriteDelay(int ticks) = 0;
|
||||
|
||||
protected:
|
||||
FILE *File;
|
||||
FileWriter *File;
|
||||
double TimePerTick; // in milliseconds
|
||||
double CurTime;
|
||||
int CurIntTime;
|
||||
|
@ -91,10 +92,10 @@ protected:
|
|||
class OPL_RDOSdump : public OPLDump
|
||||
{
|
||||
public:
|
||||
OPL_RDOSdump(FILE *file) : OPLDump(file)
|
||||
OPL_RDOSdump(FileWriter *file) : OPLDump(file)
|
||||
{
|
||||
assert(File != NULL);
|
||||
fwrite("RAWADATA\0", 1, 10, File);
|
||||
file->Write("RAWADATA\0", 10);
|
||||
NeedClockRate = true;
|
||||
}
|
||||
virtual ~OPL_RDOSdump()
|
||||
|
@ -102,8 +103,8 @@ public:
|
|||
if (File != NULL)
|
||||
{
|
||||
uint16_t endmark = 0xFFFF;
|
||||
fwrite(&endmark, 2, 1, File);
|
||||
fclose(File);
|
||||
File->Write(&endmark, 2);
|
||||
delete File;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,13 +115,13 @@ public:
|
|||
if (chipnum != CurChip)
|
||||
{
|
||||
uint8_t switcher[2] = { (uint8_t)(chipnum + 1), 2 };
|
||||
fwrite(switcher, 1, 2, File);
|
||||
File->Write(switcher, 2);
|
||||
}
|
||||
reg &= 255;
|
||||
if (reg != 0 && reg != 2 && (reg != 255 || v != 255))
|
||||
{
|
||||
uint8_t cmd[2] = { uint8_t(v), uint8_t(reg) };
|
||||
fwrite(cmd, 1, 2, File);
|
||||
File->Write(cmd, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,15 +147,15 @@ public:
|
|||
if (NeedClockRate)
|
||||
{ // Set the initial clock rate.
|
||||
clock_word = LittleShort(clock_word);
|
||||
fseek(File, 8, SEEK_SET);
|
||||
fwrite(&clock_word, 2, 1, File);
|
||||
fseek(File, 0, SEEK_END);
|
||||
File->Seek(8, SEEK_SET);
|
||||
File->Write(&clock_word, 2);
|
||||
File->Seek(0, SEEK_END);
|
||||
NeedClockRate = false;
|
||||
}
|
||||
else
|
||||
{ // Change the clock rate in the middle of the song.
|
||||
uint8_t clock_change[4] = { 0, 2, uint8_t(clock_word & 255), uint8_t(clock_word >> 8) };
|
||||
fwrite(clock_change, 1, 4, File);
|
||||
File->Write(clock_change, 4);
|
||||
}
|
||||
}
|
||||
virtual void WriteDelay(int ticks)
|
||||
|
@ -170,10 +171,10 @@ public:
|
|||
{
|
||||
ticks -= 255;
|
||||
delay[0] = 255;
|
||||
fwrite(delay, 1, 2, File);
|
||||
File->Write(delay, 2);
|
||||
}
|
||||
delay[0] = uint8_t(ticks);
|
||||
fwrite(delay, 1, 2, File);
|
||||
File->Write(delay, 2);
|
||||
}
|
||||
}
|
||||
protected:
|
||||
|
@ -183,30 +184,30 @@ protected:
|
|||
class OPL_DOSBOXdump : public OPLDump
|
||||
{
|
||||
public:
|
||||
OPL_DOSBOXdump(FILE *file, bool dual) : OPLDump(file), Dual(dual)
|
||||
OPL_DOSBOXdump(FileWriter *file, bool dual) : OPLDump(file), Dual(dual)
|
||||
{
|
||||
assert(File != NULL);
|
||||
fwrite("DBRAWOPL"
|
||||
File->Write("DBRAWOPL"
|
||||
"\0\0" // Minor version number
|
||||
"\1\0" // Major version number
|
||||
"\0\0\0\0" // Total milliseconds
|
||||
"\0\0\0", // Total data
|
||||
1, 20, File);
|
||||
20);
|
||||
char type[4] = { (char)(Dual * 2), 0, 0, 0 }; // Single or dual OPL-2
|
||||
fwrite(type, 1, 4, File);
|
||||
File->Write(type, 4);
|
||||
}
|
||||
virtual ~OPL_DOSBOXdump()
|
||||
{
|
||||
if (File != NULL)
|
||||
{
|
||||
long where_am_i = ftell(File);
|
||||
long where_am_i =File->Tell();
|
||||
uint32_t len[2];
|
||||
|
||||
fseek(File, 12, SEEK_SET);
|
||||
File->Seek(12, SEEK_SET);
|
||||
len[0] = LittleLong(CurIntTime);
|
||||
len[1] = LittleLong(uint32_t(where_am_i - 24));
|
||||
fwrite(len, 4, 2, File);
|
||||
fclose(File);
|
||||
File->Write(len, 8);
|
||||
delete File;
|
||||
}
|
||||
}
|
||||
virtual void WriteReg(int reg, int v)
|
||||
|
@ -216,11 +217,12 @@ public:
|
|||
if (chipnum != CurChip)
|
||||
{
|
||||
CurChip = chipnum;
|
||||
fputc(chipnum + 2, File);
|
||||
chipnum += 2;
|
||||
File->Write(&chipnum, 1);
|
||||
}
|
||||
reg &= 255;
|
||||
uint8_t cmd[3] = { 4, uint8_t(reg), uint8_t(v) };
|
||||
fwrite (cmd + (reg > 4), 1, 3 - (reg > 4), File);
|
||||
File->Write(cmd + (reg > 4), 3 - (reg > 4));
|
||||
}
|
||||
virtual void WriteDelay(int ticks)
|
||||
{
|
||||
|
@ -234,20 +236,20 @@ public:
|
|||
while (delay > 65536)
|
||||
{
|
||||
uint8_t cmd[3] = { 1, 255, 255 };
|
||||
fwrite(cmd, 1, 2, File);
|
||||
File->Write(cmd, 2);
|
||||
delay -= 65536;
|
||||
}
|
||||
delay--;
|
||||
if (delay <= 255)
|
||||
{
|
||||
uint8_t cmd[2] = { 0, uint8_t(delay) };
|
||||
fwrite(cmd, 1, 2, File);
|
||||
File->Write(cmd, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(delay <= 65535);
|
||||
uint8_t cmd[3] = { 1, uint8_t(delay & 255), uint8_t(delay >> 8) };
|
||||
fwrite(cmd, 1, 3, File);
|
||||
File->Write(cmd, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -338,7 +340,7 @@ DiskWriterIO::~DiskWriterIO()
|
|||
|
||||
int DiskWriterIO::Init(uint32_t numchips, bool, bool initopl3)
|
||||
{
|
||||
FILE *file = fopen(Filename, "wb");
|
||||
FileWriter *file = FileWriter::Open(Filename);
|
||||
if (file == NULL)
|
||||
{
|
||||
Printf("Could not open %s for writing.\n", Filename.GetChars());
|
||||
|
|
|
@ -89,7 +89,7 @@ struct FmtChunk
|
|||
|
||||
TimidityMIDIDevice::TimidityMIDIDevice(const char *args)
|
||||
{
|
||||
Renderer = NULL;
|
||||
Renderer = nullptr;
|
||||
Renderer = new Timidity::Renderer((float)SampleRate, args);
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ TimidityMIDIDevice::TimidityMIDIDevice(const char *args)
|
|||
TimidityMIDIDevice::~TimidityMIDIDevice()
|
||||
{
|
||||
Close();
|
||||
if (Renderer != NULL)
|
||||
if (Renderer != nullptr)
|
||||
{
|
||||
delete Renderer;
|
||||
}
|
||||
|
@ -246,10 +246,10 @@ FString TimidityMIDIDevice::GetStats()
|
|||
//==========================================================================
|
||||
|
||||
TimidityWaveWriterMIDIDevice::TimidityWaveWriterMIDIDevice(const char *filename, int rate)
|
||||
:TimidityMIDIDevice(NULL)
|
||||
:TimidityMIDIDevice(nullptr)
|
||||
{
|
||||
File = fopen(filename, "wb");
|
||||
if (File != NULL)
|
||||
File = FileWriter::Open(filename);
|
||||
if (File != nullptr)
|
||||
{ // Write wave header
|
||||
uint32_t work[3];
|
||||
FmtChunk fmt;
|
||||
|
@ -257,7 +257,7 @@ TimidityWaveWriterMIDIDevice::TimidityWaveWriterMIDIDevice(const char *filename,
|
|||
work[0] = MAKE_ID('R','I','F','F');
|
||||
work[1] = 0; // filled in later
|
||||
work[2] = MAKE_ID('W','A','V','E');
|
||||
if (3 != fwrite(work, 4, 3, File)) goto fail;
|
||||
if (4*3 != File->Write(work, 4 * 3)) goto fail;
|
||||
|
||||
fmt.ChunkID = MAKE_ID('f','m','t',' ');
|
||||
fmt.ChunkLen = LittleLong(uint32_t(sizeof(fmt) - 8));
|
||||
|
@ -281,17 +281,17 @@ TimidityWaveWriterMIDIDevice::TimidityWaveWriterMIDIDevice(const char *filename,
|
|||
fmt.SubFormatD[5] = 0x38;
|
||||
fmt.SubFormatD[6] = 0x9b;
|
||||
fmt.SubFormatD[7] = 0x71;
|
||||
if (1 != fwrite(&fmt, sizeof(fmt), 1, File)) goto fail;
|
||||
if (sizeof(fmt) != File->Write(&fmt, sizeof(fmt))) goto fail;
|
||||
|
||||
work[0] = MAKE_ID('d','a','t','a');
|
||||
work[1] = 0; // filled in later
|
||||
if (2 != fwrite(work, 4, 2, File)) goto fail;
|
||||
if (8 !=File->Write(work, 8)) goto fail;
|
||||
|
||||
return;
|
||||
fail:
|
||||
Printf("Failed to write %s: %s\n", filename, strerror(errno));
|
||||
fclose(File);
|
||||
File = NULL;
|
||||
delete File;
|
||||
File = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,30 +303,30 @@ fail:
|
|||
|
||||
TimidityWaveWriterMIDIDevice::~TimidityWaveWriterMIDIDevice()
|
||||
{
|
||||
if (File != NULL)
|
||||
if (File != nullptr)
|
||||
{
|
||||
long pos = ftell(File);
|
||||
long pos = File->Tell();
|
||||
uint32_t size;
|
||||
|
||||
// data chunk size
|
||||
size = LittleLong(uint32_t(pos - 8));
|
||||
if (0 == fseek(File, 4, SEEK_SET))
|
||||
if (0 == File->Seek(4, SEEK_SET))
|
||||
{
|
||||
if (1 == fwrite(&size, 4, 1, File))
|
||||
if (4 == File->Write(&size, 4))
|
||||
{
|
||||
size = LittleLong(uint32_t(pos - 12 - sizeof(FmtChunk) - 8));
|
||||
if (0 == fseek(File, 4 + sizeof(FmtChunk) + 4, SEEK_CUR))
|
||||
if (0 == File->Seek(4 + sizeof(FmtChunk) + 4, SEEK_CUR))
|
||||
{
|
||||
if (1 == fwrite(&size, 4, 1, File))
|
||||
if (1 == File->Write(&size, 4))
|
||||
{
|
||||
fclose(File);
|
||||
delete File;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Printf("Could not finish writing wave file: %s\n", strerror(errno));
|
||||
fclose(File);
|
||||
delete File;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -342,7 +342,7 @@ int TimidityWaveWriterMIDIDevice::Resume()
|
|||
|
||||
while (ServiceStream(writebuffer, sizeof(writebuffer)))
|
||||
{
|
||||
if (fwrite(writebuffer, sizeof(writebuffer), 1, File) != 1)
|
||||
if (File->Write(writebuffer, sizeof(writebuffer)) != sizeof(writebuffer))
|
||||
{
|
||||
Printf("Could not write entire wave file: %s\n", strerror(errno));
|
||||
return 1;
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "templates.h"
|
||||
#include "version.h"
|
||||
#include "tmpfileplus.h"
|
||||
#include "m_misc.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
|
@ -82,7 +83,7 @@ public:
|
|||
protected:
|
||||
bool LaunchTimidity();
|
||||
|
||||
char* DiskName;
|
||||
FString DiskName;
|
||||
#ifdef _WIN32
|
||||
HANDLE ReadWavePipe;
|
||||
HANDLE WriteWavePipe;
|
||||
|
@ -165,8 +166,7 @@ CUSTOM_CVAR (Int, timidity_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args)
|
||||
: DiskName(nullptr),
|
||||
TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) :
|
||||
#ifdef _WIN32
|
||||
ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE),
|
||||
ChildProcess(INVALID_HANDLE_VALUE),
|
||||
|
@ -204,10 +204,9 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args)
|
|||
|
||||
TimidityPPMIDIDevice::~TimidityPPMIDIDevice ()
|
||||
{
|
||||
if (nullptr != DiskName)
|
||||
if (DiskName.IsNotEmpty())
|
||||
{
|
||||
remove(DiskName);
|
||||
free(DiskName);
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
|
@ -257,7 +256,10 @@ bool TimidityPPMIDIDevice::Preprocess(MIDIStreamer *song, bool looping)
|
|||
// Write MIDI song to temporary file
|
||||
song->CreateSMF(midi, looping ? 0 : 1);
|
||||
|
||||
f = tmpfileplus(nullptr, "zmid", &DiskName, 1);
|
||||
FString path = M_GetAppDataPath(false);
|
||||
path += "/tmp";
|
||||
CreatePath(path);
|
||||
f = tmpfileplus(path, "zmid", &DiskName, 1);
|
||||
if (f == NULL)
|
||||
{
|
||||
Printf(PRINT_BOLD, "Could not open temp music file\n");
|
||||
|
@ -454,7 +456,7 @@ bool TimidityPPMIDIDevice::ValidateTimidity()
|
|||
|
||||
bool TimidityPPMIDIDevice::LaunchTimidity ()
|
||||
{
|
||||
if (ExeName.IsEmpty() || nullptr == DiskName)
|
||||
if (ExeName.IsEmpty() || DiskName.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -565,7 +567,7 @@ bool TimidityPPMIDIDevice::LaunchTimidity ()
|
|||
arglist.push_back("-");
|
||||
arglist.push_back(outmodearg.c_str());
|
||||
arglist.push_back(ifacearg.c_str());
|
||||
arglist.push_back(DiskName);
|
||||
arglist.push_back(DiskName.GetChars());
|
||||
|
||||
DPrintf(DMSG_NOTIFY, "Timidity EXE: \x1cG%s\n", exename);
|
||||
int i = 1;
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
#include "m_crc32.h"
|
||||
#include "serializer.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "files.h"
|
||||
|
||||
CVAR(Int, savestatistics, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR(String, statfile, "zdoomstat.txt", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
@ -136,7 +137,7 @@ static void ParseStatistics(const char *fn, TArray<FStatistics> &statlist)
|
|||
try
|
||||
{
|
||||
FScanner sc;
|
||||
sc.OpenFile(fn);
|
||||
if (!sc.OpenFile(fn)) return;
|
||||
|
||||
while (sc.GetString())
|
||||
{
|
||||
|
@ -260,8 +261,8 @@ static void SaveStatistics(const char *fn, TArray<FStatistics> &statlist)
|
|||
{
|
||||
unsigned int j;
|
||||
|
||||
FILE * f = fopen(fn, "wt");
|
||||
if (f==NULL) return;
|
||||
FileWriter *fw = FileWriter::Open(fn);
|
||||
if (fw == nullptr) return;
|
||||
|
||||
qsort(&statlist[0], statlist.Size(), sizeof(statlist[0]), compare_episode_names);
|
||||
for(unsigned i=0;i<statlist.Size ();i++)
|
||||
|
@ -270,34 +271,34 @@ static void SaveStatistics(const char *fn, TArray<FStatistics> &statlist)
|
|||
|
||||
qsort(&ep_stats.stats[0], ep_stats.stats.Size(), sizeof(ep_stats.stats[0]), compare_dates);
|
||||
|
||||
fprintf(f, "%s \"%s\"\n{\n", ep_stats.epi_header.GetChars(), ep_stats.epi_name.GetChars());
|
||||
fw->Printf("%s \"%s\"\n{\n", ep_stats.epi_header.GetChars(), ep_stats.epi_name.GetChars());
|
||||
for(j=0;j<ep_stats.stats.Size();j++)
|
||||
{
|
||||
FSessionStatistics *sst = &ep_stats.stats[j];
|
||||
if (sst->info[0]>0)
|
||||
{
|
||||
fprintf(f,"\t%2i. %10s \"%-22s\" %02d:%02d:%02d %i\n", j+1, sst->name, sst->info,
|
||||
fw->Printf("\t%2i. %10s \"%-22s\" %02d:%02d:%02d %i\n", j+1, sst->name, sst->info,
|
||||
hours(sst->timeneeded), minutes(sst->timeneeded), seconds(sst->timeneeded), sst->skill);
|
||||
|
||||
TArray<FLevelStatistics> &ls = sst->levelstats;
|
||||
if (ls.Size() > 0)
|
||||
{
|
||||
fprintf(f,"\t{\n");
|
||||
fw->Printf("\t{\n");
|
||||
|
||||
qsort(&ls[0], ls.Size(), sizeof(ls[0]), compare_level_names);
|
||||
|
||||
for(unsigned k=0;k<ls.Size ();k++)
|
||||
{
|
||||
fprintf(f, "\t\t%-8s \"%-22s\" %02d:%02d:%02d\n", ls[k].name, ls[k].info,
|
||||
fw->Printf("\t\t%-8s \"%-22s\" %02d:%02d:%02d\n", ls[k].name, ls[k].info,
|
||||
hours(ls[k].timeneeded), minutes(ls[k].timeneeded), seconds(ls[k].timeneeded));
|
||||
}
|
||||
fprintf(f,"\t}\n");
|
||||
fw->Printf("\t}\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(f,"}\n\n");
|
||||
fw->Printf("}\n\n");
|
||||
}
|
||||
fclose(f);
|
||||
delete fw;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -215,4 +215,125 @@ namespace swrenderer
|
|||
fuzzpos = (fuzzpos + yh - yl + 1) % FUZZTABLE;
|
||||
}
|
||||
}
|
||||
|
||||
class DepthColumnCommand : public DrawerCommand
|
||||
{
|
||||
public:
|
||||
DepthColumnCommand(const WallDrawerArgs &args, float idepth) : idepth(idepth)
|
||||
{
|
||||
auto rendertarget = args.Viewport()->RenderTarget;
|
||||
if (rendertarget->IsBgra())
|
||||
{
|
||||
uint32_t *destorg = (uint32_t*)rendertarget->GetBuffer();
|
||||
uint32_t *dest = (uint32_t*)args.Dest();
|
||||
int offset = (int)(ptrdiff_t)(dest - destorg);
|
||||
x = offset % rendertarget->GetPitch();
|
||||
y = offset / rendertarget->GetPitch();
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t *destorg = rendertarget->GetBuffer();
|
||||
uint8_t *dest = (uint8_t*)args.Dest();
|
||||
int offset = (int)(ptrdiff_t)(dest - destorg);
|
||||
x = offset % rendertarget->GetPitch();
|
||||
y = offset / rendertarget->GetPitch();
|
||||
}
|
||||
count = args.Count();
|
||||
}
|
||||
|
||||
DepthColumnCommand(const SkyDrawerArgs &args, float idepth) : idepth(idepth)
|
||||
{
|
||||
auto rendertarget = args.Viewport()->RenderTarget;
|
||||
if (rendertarget->IsBgra())
|
||||
{
|
||||
uint32_t *destorg = (uint32_t*)rendertarget->GetBuffer();
|
||||
uint32_t *dest = (uint32_t*)args.Dest();
|
||||
int offset = (int)(ptrdiff_t)(dest - destorg);
|
||||
x = offset % rendertarget->GetPitch();
|
||||
y = offset / rendertarget->GetPitch();
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t *destorg = rendertarget->GetBuffer();
|
||||
uint8_t *dest = (uint8_t*)args.Dest();
|
||||
int offset = (int)(ptrdiff_t)(dest - destorg);
|
||||
x = offset % rendertarget->GetPitch();
|
||||
y = offset / rendertarget->GetPitch();
|
||||
}
|
||||
count = args.Count();
|
||||
}
|
||||
|
||||
FString DebugInfo() override { return "DepthColumnCommand"; }
|
||||
|
||||
void Execute(DrawerThread *thread) override
|
||||
{
|
||||
auto zbuffer = PolyZBuffer::Instance();
|
||||
int pitch = PolyStencilBuffer::Instance()->BlockWidth() * 8;
|
||||
float *values = zbuffer->Values() + y * pitch + x;
|
||||
int cnt = count;
|
||||
|
||||
values = thread->dest_for_thread(y, pitch, values);
|
||||
cnt = thread->count_for_thread(y, cnt);
|
||||
pitch *= thread->num_cores;
|
||||
|
||||
float depth = idepth;
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
*values = depth;
|
||||
values += pitch;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int x, y, count;
|
||||
float idepth;
|
||||
};
|
||||
|
||||
class DepthSpanCommand : public DrawerCommand
|
||||
{
|
||||
public:
|
||||
DepthSpanCommand(const SpanDrawerArgs &args, float idepth) : idepth(idepth)
|
||||
{
|
||||
y = args.DestY();
|
||||
x1 = args.DestX1();
|
||||
x2 = args.DestX2();
|
||||
}
|
||||
|
||||
FString DebugInfo() override { return "DepthSpanCommand"; }
|
||||
|
||||
void Execute(DrawerThread *thread) override
|
||||
{
|
||||
if (thread->skipped_by_thread(y))
|
||||
return;
|
||||
|
||||
auto zbuffer = PolyZBuffer::Instance();
|
||||
int pitch = PolyStencilBuffer::Instance()->BlockWidth() * 8;
|
||||
float *values = zbuffer->Values() + y * pitch;
|
||||
int end = x2;
|
||||
float depth = idepth;
|
||||
for (int x = x1; x <= end; x++)
|
||||
{
|
||||
values[x] = depth;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int y, x1, x2;
|
||||
float idepth;
|
||||
};
|
||||
|
||||
void SWPixelFormatDrawers::DrawDepthSkyColumn(const SkyDrawerArgs &args, float idepth)
|
||||
{
|
||||
Queue->Push<DepthColumnCommand>(args, idepth);
|
||||
}
|
||||
|
||||
void SWPixelFormatDrawers::DrawDepthWallColumn(const WallDrawerArgs &args, float idepth)
|
||||
{
|
||||
Queue->Push<DepthColumnCommand>(args, idepth);
|
||||
}
|
||||
|
||||
void SWPixelFormatDrawers::DrawDepthSpan(const SpanDrawerArgs &args, float idepth)
|
||||
{
|
||||
Queue->Push<DepthSpanCommand>(args, idepth);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,10 @@ namespace swrenderer
|
|||
virtual void DrawColoredSpan(const SpanDrawerArgs &args) = 0;
|
||||
virtual void DrawFogBoundaryLine(const SpanDrawerArgs &args) = 0;
|
||||
|
||||
void DrawDepthSkyColumn(const SkyDrawerArgs &args, float idepth);
|
||||
void DrawDepthWallColumn(const WallDrawerArgs &args, float idepth);
|
||||
void DrawDepthSpan(const SpanDrawerArgs &args, float idepth);
|
||||
|
||||
DrawerCommandQueuePtr Queue;
|
||||
};
|
||||
|
||||
|
|
|
@ -177,16 +177,18 @@ namespace swrenderer
|
|||
// Draw a column with support for non-power-of-two ranges
|
||||
void RenderWallPart::Draw1Column(int x, int y1, int y2, WallSampler &sampler)
|
||||
{
|
||||
// Find column position in view space
|
||||
float w1 = 1.0f / WallC.sz1;
|
||||
float w2 = 1.0f / WallC.sz2;
|
||||
float t = (x - WallC.sx1 + 0.5f) / (WallC.sx2 - WallC.sx1);
|
||||
float wcol = w1 * (1.0f - t) + w2 * t;
|
||||
float zcol = 1.0f / wcol;
|
||||
float zbufferdepth = 1.0f / (zcol / Thread->Viewport->viewwindow.FocalTangent);
|
||||
|
||||
if (r_dynlights && light_list)
|
||||
{
|
||||
auto viewport = Thread->Viewport.get();
|
||||
|
||||
// Find column position in view space
|
||||
float w1 = 1.0f / WallC.sz1;
|
||||
float w2 = 1.0f / WallC.sz2;
|
||||
float t = (x - WallC.sx1 + 0.5f) / (WallC.sx2 - WallC.sx1);
|
||||
float wcol = w1 * (1.0f - t) + w2 * t;
|
||||
float zcol = 1.0f / wcol;
|
||||
drawerargs.dc_viewpos.X = (float)((x + 0.5 - viewport->CenterX) / viewport->CenterX * zcol);
|
||||
drawerargs.dc_viewpos.Y = zcol;
|
||||
drawerargs.dc_viewpos.Z = (float)((viewport->CenterY - y1 - 0.5) / viewport->InvZtoScale * zcol);
|
||||
|
@ -260,6 +262,8 @@ namespace swrenderer
|
|||
drawerargs.SetTextureVStep(sampler.uv_step);
|
||||
drawerargs.SetTextureVPos(sampler.uv_pos);
|
||||
drawerargs.DrawColumn(Thread);
|
||||
if (r_models)
|
||||
drawerargs.DrawDepthColumn(Thread, zbufferdepth);
|
||||
|
||||
uint64_t step64 = sampler.uv_step;
|
||||
uint64_t pos64 = sampler.uv_pos;
|
||||
|
@ -278,6 +282,8 @@ namespace swrenderer
|
|||
drawerargs.SetTextureVStep(sampler.uv_step);
|
||||
drawerargs.SetTextureVPos(sampler.uv_pos);
|
||||
drawerargs.DrawColumn(Thread);
|
||||
if (r_models)
|
||||
drawerargs.DrawDepthColumn(Thread, zbufferdepth);
|
||||
|
||||
uint64_t step64 = sampler.uv_step;
|
||||
uint64_t pos64 = sampler.uv_pos;
|
||||
|
@ -304,6 +310,8 @@ namespace swrenderer
|
|||
drawerargs.SetTextureVStep(sampler.uv_step);
|
||||
drawerargs.SetTextureVPos(uv_pos);
|
||||
drawerargs.DrawColumn(Thread);
|
||||
if (r_models)
|
||||
drawerargs.DrawDepthColumn(Thread, zbufferdepth);
|
||||
|
||||
y += count;
|
||||
left -= count;
|
||||
|
|
|
@ -178,6 +178,7 @@ namespace swrenderer
|
|||
double curyfrac = baseyfrac + ystepscale * (x1 - minx);
|
||||
|
||||
double distance = viewport->PlaneDepth(y, planeheight);
|
||||
float zbufferdepth = 1.0f / (distance * Thread->Viewport->viewwindow.FocalTangent);
|
||||
|
||||
drawerargs.SetTextureUStep(distance * xstepscale / drawerargs.TextureWidth());
|
||||
drawerargs.SetTextureUPos((distance * curxfrac + pviewx) / drawerargs.TextureWidth());
|
||||
|
@ -274,6 +275,8 @@ namespace swrenderer
|
|||
drawerargs.SetDestX2(x2);
|
||||
|
||||
drawerargs.DrawSpan(Thread);
|
||||
if (r_models)
|
||||
drawerargs.DrawDepthSpan(Thread, zbufferdepth);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -224,6 +224,9 @@ namespace swrenderer
|
|||
drawerargs.DrawSingleSkyColumn(Thread);
|
||||
else
|
||||
drawerargs.DrawDoubleSkyColumn(Thread);
|
||||
|
||||
if (r_models)
|
||||
drawerargs.DrawDepthSkyColumn(Thread, 1.0f / 65536.0f);
|
||||
}
|
||||
|
||||
void RenderSkyPlane::DrawSkyColumn(int start_x, int y1, int y2)
|
||||
|
|
|
@ -205,6 +205,15 @@ namespace swrenderer
|
|||
|
||||
void RenderSlopePlane::RenderLine(int y, int x1, int x2)
|
||||
{
|
||||
/* To do: project (x1,y) and (x2,y) on the plane to calculate the depth
|
||||
double distance = Thread->Viewport->PlaneDepth(y, planeheight);
|
||||
float zbufferdepth = 1.0f / (distance * Thread->Viewport->viewwindow.FocalTangent);
|
||||
drawerargs.SetDestX1(x1);
|
||||
drawerargs.SetDestX2(x2);
|
||||
drawerargs.SetDestY(Thread->Viewport.get(), y);
|
||||
drawerargs.DrawDepthSpan(Thread, zbufferdepth);
|
||||
*/
|
||||
|
||||
drawerargs.DrawTiltedSpan(Thread, y, x1, x2, plane_sz, plane_su, plane_sv, plane_shade, planeshade, planelightfloat, pviewx, pviewy, basecolormap);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "things/r_visiblespritelist.cpp"
|
||||
#include "things/r_voxel.cpp"
|
||||
#include "things/r_wallsprite.cpp"
|
||||
#include "things/r_model.cpp"
|
||||
#include "viewport/r_drawerargs.cpp"
|
||||
#include "viewport/r_skydrawer.cpp"
|
||||
#include "viewport/r_spandrawer.cpp"
|
||||
|
|
|
@ -29,6 +29,8 @@ class DrawerCommandQueue;
|
|||
typedef std::shared_ptr<DrawerCommandQueue> DrawerCommandQueuePtr;
|
||||
class RenderMemory;
|
||||
|
||||
EXTERN_CVAR(Bool, r_models);
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
class VisibleSpriteList;
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "swrenderer/things/r_wallsprite.h"
|
||||
#include "swrenderer/things/r_voxel.h"
|
||||
#include "swrenderer/things/r_particle.h"
|
||||
#include "swrenderer/things/r_model.h"
|
||||
#include "swrenderer/segments/r_clipsegment.h"
|
||||
#include "swrenderer/line/r_wallsetup.h"
|
||||
#include "swrenderer/line/r_farclip_line.h"
|
||||
|
@ -79,6 +80,7 @@ namespace
|
|||
{
|
||||
double sprite_distance_cull = 1e16;
|
||||
double line_distance_cull = 1e16;
|
||||
double model_distance_cull = 1e16;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, r_sprite_distance_cull, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
@ -105,6 +107,18 @@ CUSTOM_CVAR(Float, r_line_distance_cull, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
|||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, r_model_distance_cull, 1024, 0/*CVAR_ARCHIVE | CVAR_GLOBALCONFIG*/) // Experimental for the moment until a good default is chosen
|
||||
{
|
||||
if (r_model_distance_cull > 0.0)
|
||||
{
|
||||
model_distance_cull = r_model_distance_cull * r_model_distance_cull;
|
||||
}
|
||||
else
|
||||
{
|
||||
model_distance_cull = 1e16;
|
||||
}
|
||||
}
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
RenderOpaquePass::RenderOpaquePass(RenderThread *thread) : renderline(thread)
|
||||
|
@ -949,10 +963,25 @@ namespace swrenderer
|
|||
{
|
||||
RenderVoxel::Project(Thread, thing, sprite.pos, sprite.voxel, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thingShade, foggy, thingColormap);
|
||||
}
|
||||
else
|
||||
else if (!r_models)
|
||||
{
|
||||
RenderSprite::Project(Thread, thing, sprite.pos, sprite.tex, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thingShade, foggy, thingColormap);
|
||||
}
|
||||
else
|
||||
{
|
||||
int spritenum = thing->sprite;
|
||||
bool isPicnumOverride = thing->picnum.isValid();
|
||||
FSpriteModelFrame *modelframe = isPicnumOverride ? nullptr : gl_FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED));
|
||||
if (modelframe && (thing->Pos() - Thread->Viewport->viewpoint.Pos).LengthSquared() < model_distance_cull)
|
||||
{
|
||||
DVector3 pos = thing->InterpolatedPosition(Thread->Viewport->viewpoint.TicFrac);
|
||||
RenderModel::Project(Thread, (float)pos.X, (float)pos.Y, (float)pos.Z, modelframe, thing);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderSprite::Project(Thread, thing, sprite.pos, sprite.tex, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thingShade, foggy, thingColormap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ EXTERN_CVAR(Bool, r_shadercolormaps)
|
|||
EXTERN_CVAR(Int, r_clearbuffer)
|
||||
|
||||
CVAR(Bool, r_scene_multithreaded, false, 0);
|
||||
CVAR(Bool, r_models, false, 0);
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
|
@ -156,6 +157,9 @@ namespace swrenderer
|
|||
|
||||
R_UpdateFuzzPosFrameStart();
|
||||
|
||||
if (r_models)
|
||||
MainThread()->Viewport->SetupPolyViewport();
|
||||
|
||||
ActorRenderFlags savedflags = MainThread()->Viewport->viewpoint.camera->renderflags;
|
||||
// Never draw the player unless in chasecam mode
|
||||
if (!MainThread()->Viewport->viewpoint.showviewer)
|
||||
|
|
326
src/swrenderer/things/r_model.cpp
Normal file
326
src/swrenderer/things/r_model.cpp
Normal file
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
** 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 "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "r_model.h"
|
||||
#include "r_data/r_vanillatrans.h"
|
||||
#include "actorinlines.h"
|
||||
#include "i_time.h"
|
||||
#include "swrenderer/r_memory.h"
|
||||
#include "swrenderer/r_swcolormaps.h"
|
||||
#include "swrenderer/viewport/r_viewport.h"
|
||||
#include "swrenderer/scene/r_light.h"
|
||||
|
||||
void gl_FlushModels();
|
||||
extern bool polymodelsInUse;
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
void RenderModel::Project(RenderThread *thread, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor)
|
||||
{
|
||||
// transform the origin point
|
||||
double tr_x = x - thread->Viewport->viewpoint.Pos.X;
|
||||
double tr_y = y - thread->Viewport->viewpoint.Pos.Y;
|
||||
double tz = tr_x * thread->Viewport->viewpoint.TanCos + tr_y * thread->Viewport->viewpoint.TanSin;
|
||||
|
||||
// thing is behind view plane?
|
||||
if (tz < MINZ)
|
||||
return;
|
||||
|
||||
// too far off the side?
|
||||
double tx = tr_x * thread->Viewport->viewpoint.Sin - tr_y * thread->Viewport->viewpoint.Cos;
|
||||
if (fabs(tx / 64) > fabs(tz))
|
||||
return;
|
||||
|
||||
RenderModel *vis = thread->FrameMemory->NewObject<RenderModel>(x, y, z, smf, actor, float(1 / tz));
|
||||
thread->SpriteList->Push(vis);
|
||||
}
|
||||
|
||||
RenderModel::RenderModel(float x, float y, float z, FSpriteModelFrame *smf, AActor *actor, float idepth) : x(x), y(y), z(z), smf(smf), actor(actor)
|
||||
{
|
||||
this->idepth = idepth;
|
||||
}
|
||||
|
||||
void RenderModel::Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ)
|
||||
{
|
||||
SWModelRenderer renderer(thread);
|
||||
renderer.RenderModel(x, y, z, smf, actor);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RenderHUDModel(RenderThread *thread, DPSprite *psp, float ofsx, float ofsy)
|
||||
{
|
||||
SWModelRenderer renderer(thread);
|
||||
renderer.RenderHUDModel(psp, ofsx, ofsy);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SWModelRenderer::SWModelRenderer(RenderThread *thread) : Thread(thread)
|
||||
{
|
||||
if (polymodelsInUse)
|
||||
{
|
||||
gl_FlushModels();
|
||||
polymodelsInUse = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SWModelRenderer::BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix)
|
||||
{
|
||||
ModelActor = actor;
|
||||
const_cast<VSMatrix &>(objectToWorldMatrix).copy(ObjectToWorld.matrix);
|
||||
}
|
||||
|
||||
void SWModelRenderer::EndDrawModel(AActor *actor, FSpriteModelFrame *smf)
|
||||
{
|
||||
ModelActor = nullptr;
|
||||
}
|
||||
|
||||
IModelVertexBuffer *SWModelRenderer::CreateVertexBuffer(bool needindex, bool singleframe)
|
||||
{
|
||||
return new SWModelVertexBuffer(needindex, singleframe);
|
||||
}
|
||||
|
||||
void SWModelRenderer::SetVertexBuffer(IModelVertexBuffer *buffer)
|
||||
{
|
||||
}
|
||||
|
||||
void SWModelRenderer::ResetVertexBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
VSMatrix SWModelRenderer::GetViewToWorldMatrix()
|
||||
{
|
||||
// Calculate the WorldToView matrix as it would have looked like without yshearing:
|
||||
const auto &Viewpoint = Thread->Viewport->viewpoint;
|
||||
const auto &Viewwindow = Thread->Viewport->viewwindow;
|
||||
double radPitch = Viewpoint.Angles.Pitch.Normalized180().Radians();
|
||||
double angx = cos(radPitch);
|
||||
double angy = sin(radPitch) * level.info->pixelstretch;
|
||||
double alen = sqrt(angx*angx + angy*angy);
|
||||
float adjustedPitch = (float)asin(angy / alen);
|
||||
float adjustedViewAngle = (float)(Viewpoint.Angles.Yaw - 90).Radians();
|
||||
float ratio = Viewwindow.WidescreenRatio;
|
||||
float fovratio = (Viewwindow.WidescreenRatio >= 1.3f) ? 1.333333f : ratio;
|
||||
float fovy = (float)(2 * DAngle::ToDegrees(atan(tan(Viewpoint.FieldOfView.Radians() / 2) / fovratio)).Degrees);
|
||||
TriMatrix altWorldToView =
|
||||
TriMatrix::rotate(adjustedPitch, 1.0f, 0.0f, 0.0f) *
|
||||
TriMatrix::rotate(adjustedViewAngle, 0.0f, -1.0f, 0.0f) *
|
||||
TriMatrix::scale(1.0f, level.info->pixelstretch, 1.0f) *
|
||||
TriMatrix::swapYZ() *
|
||||
TriMatrix::translate((float)-Viewpoint.Pos.X, (float)-Viewpoint.Pos.Y, (float)-Viewpoint.Pos.Z);
|
||||
|
||||
TriMatrix swapYZ = TriMatrix::null();
|
||||
swapYZ.matrix[0 + 0 * 4] = 1.0f;
|
||||
swapYZ.matrix[1 + 2 * 4] = 1.0f;
|
||||
swapYZ.matrix[2 + 1 * 4] = 1.0f;
|
||||
swapYZ.matrix[3 + 3 * 4] = 1.0f;
|
||||
|
||||
VSMatrix worldToView;
|
||||
worldToView.loadMatrix((altWorldToView * swapYZ).matrix);
|
||||
|
||||
VSMatrix objectToWorld;
|
||||
worldToView.inverseMatrix(objectToWorld);
|
||||
return objectToWorld;
|
||||
}
|
||||
|
||||
void SWModelRenderer::BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix)
|
||||
{
|
||||
ModelActor = actor;
|
||||
const_cast<VSMatrix &>(objectToWorldMatrix).copy(ObjectToWorld.matrix);
|
||||
}
|
||||
|
||||
void SWModelRenderer::EndDrawHUDModel(AActor *actor)
|
||||
{
|
||||
ModelActor = nullptr;
|
||||
}
|
||||
|
||||
void SWModelRenderer::SetInterpolation(double interpolation)
|
||||
{
|
||||
InterpolationFactor = (float)interpolation;
|
||||
}
|
||||
|
||||
void SWModelRenderer::SetMaterial(FTexture *skin, bool clampNoFilter, int translation)
|
||||
{
|
||||
SkinTexture = skin;
|
||||
}
|
||||
|
||||
void SWModelRenderer::DrawArrays(int start, int count)
|
||||
{
|
||||
const auto &viewpoint = Thread->Viewport->viewpoint;
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : viewpoint.extralight << 4;
|
||||
sector_t *sector = ModelActor->Sector;
|
||||
|
||||
bool fullbrightSprite = ((ModelActor->renderflags & RF_FULLBRIGHT) || (ModelActor->flags5 & MF5_BRIGHT));
|
||||
int lightlevel = fullbrightSprite ? 255 : ModelActor->Sector->lightlevel + actualextralight;
|
||||
|
||||
TriMatrix swapYZ = TriMatrix::null();
|
||||
swapYZ.matrix[0 + 0 * 4] = 1.0f;
|
||||
swapYZ.matrix[1 + 2 * 4] = 1.0f;
|
||||
swapYZ.matrix[2 + 1 * 4] = 1.0f;
|
||||
swapYZ.matrix[3 + 3 * 4] = 1.0f;
|
||||
|
||||
TriMatrix *transform = Thread->FrameMemory->NewObject<TriMatrix>();
|
||||
*transform = Thread->Viewport->WorldToClip * swapYZ * ObjectToWorld;
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(GetColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], true), lightlevel, Thread->Light->SpriteGlobVis(foggy), fullbrightSprite);
|
||||
args.SetTransform(transform);
|
||||
args.SetFaceCullCCW(true);
|
||||
args.SetClipPlane(0, PolyClipPlane());
|
||||
args.SetStyle(TriBlendMode::TextureOpaque);
|
||||
|
||||
if (Thread->Viewport->RenderTarget->IsBgra())
|
||||
args.SetTexture((const uint8_t *)SkinTexture->GetPixelsBgra(), SkinTexture->GetWidth(), SkinTexture->GetHeight());
|
||||
else
|
||||
args.SetTexture(SkinTexture->GetPixels(), SkinTexture->GetWidth(), SkinTexture->GetHeight());
|
||||
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
args.SetWriteStencil(false);
|
||||
args.DrawArray(Thread->DrawQueue, VertexBuffer + start, count);
|
||||
}
|
||||
|
||||
void SWModelRenderer::DrawElements(int numIndices, size_t offset)
|
||||
{
|
||||
const auto &viewpoint = Thread->Viewport->viewpoint;
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : viewpoint.extralight << 4;
|
||||
sector_t *sector = ModelActor->Sector;
|
||||
|
||||
bool fullbrightSprite = ((ModelActor->renderflags & RF_FULLBRIGHT) || (ModelActor->flags5 & MF5_BRIGHT));
|
||||
int lightlevel = fullbrightSprite ? 255 : ModelActor->Sector->lightlevel + actualextralight;
|
||||
|
||||
TriMatrix swapYZ = TriMatrix::null();
|
||||
swapYZ.matrix[0 + 0 * 4] = 1.0f;
|
||||
swapYZ.matrix[1 + 2 * 4] = 1.0f;
|
||||
swapYZ.matrix[2 + 1 * 4] = 1.0f;
|
||||
swapYZ.matrix[3 + 3 * 4] = 1.0f;
|
||||
|
||||
TriMatrix *transform = Thread->FrameMemory->NewObject<TriMatrix>();
|
||||
*transform = Thread->Viewport->WorldToClip * swapYZ * ObjectToWorld;
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(GetColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], true), lightlevel, Thread->Light->SpriteGlobVis(foggy), fullbrightSprite);
|
||||
args.SetTransform(transform);
|
||||
args.SetFaceCullCCW(true);
|
||||
args.SetClipPlane(0, PolyClipPlane());
|
||||
args.SetStyle(TriBlendMode::TextureOpaque);
|
||||
|
||||
if (Thread->Viewport->RenderTarget->IsBgra())
|
||||
args.SetTexture((const uint8_t *)SkinTexture->GetPixelsBgra(), SkinTexture->GetWidth(), SkinTexture->GetHeight());
|
||||
else
|
||||
args.SetTexture(SkinTexture->GetPixels(), SkinTexture->GetWidth(), SkinTexture->GetHeight());
|
||||
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
args.SetWriteStencil(false);
|
||||
args.DrawElements(Thread->DrawQueue, VertexBuffer, IndexBuffer + offset / sizeof(unsigned int), numIndices);
|
||||
}
|
||||
|
||||
double SWModelRenderer::GetTimeFloat()
|
||||
{
|
||||
return (double)screen->FrameTime * (double)TICRATE / 1000.0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SWModelVertexBuffer::SWModelVertexBuffer(bool needindex, bool singleframe)
|
||||
{
|
||||
}
|
||||
|
||||
SWModelVertexBuffer::~SWModelVertexBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
FModelVertex *SWModelVertexBuffer::LockVertexBuffer(unsigned int size)
|
||||
{
|
||||
mVertexBuffer.Resize(size);
|
||||
return &mVertexBuffer[0];
|
||||
}
|
||||
|
||||
void SWModelVertexBuffer::UnlockVertexBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int *SWModelVertexBuffer::LockIndexBuffer(unsigned int size)
|
||||
{
|
||||
mIndexBuffer.Resize(size);
|
||||
return &mIndexBuffer[0];
|
||||
}
|
||||
|
||||
void SWModelVertexBuffer::UnlockIndexBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
void SWModelVertexBuffer::SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size)
|
||||
{
|
||||
SWModelRenderer *polyrenderer = (SWModelRenderer *)renderer;
|
||||
|
||||
if (true)//if (frame1 == frame2 || size == 0 || polyrenderer->InterpolationFactor == 0.f)
|
||||
{
|
||||
TriVertex *vertices = polyrenderer->Thread->FrameMemory->AllocMemory<TriVertex>(size);
|
||||
|
||||
for (unsigned int i = 0; i < size; i++)
|
||||
{
|
||||
vertices[i] =
|
||||
{
|
||||
mVertexBuffer[frame1 + i].x,
|
||||
mVertexBuffer[frame1 + i].y,
|
||||
mVertexBuffer[frame1 + i].z,
|
||||
1.0f,
|
||||
mVertexBuffer[frame1 + i].u,
|
||||
mVertexBuffer[frame1 + i].v
|
||||
};
|
||||
}
|
||||
|
||||
polyrenderer->VertexBuffer = vertices;
|
||||
polyrenderer->IndexBuffer = &mIndexBuffer[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
TriVertex *vertices = polyrenderer->Thread->FrameMemory->AllocMemory<TriVertex>(size);
|
||||
|
||||
float frac = polyrenderer->InterpolationFactor;
|
||||
for (unsigned int i = 0; i < size; i++)
|
||||
{
|
||||
vertices[i].x = mVertexBuffer[frame1 + i].x * (1.0f - frac) + mVertexBuffer[frame2 + i].x * frac;
|
||||
vertices[i].y = mVertexBuffer[frame1 + i].y * (1.0f - frac) + mVertexBuffer[frame2 + i].y * frac;
|
||||
vertices[i].z = mVertexBuffer[frame1 + i].z * (1.0f - frac) + mVertexBuffer[frame2 + i].z * frac;
|
||||
vertices[i].w = 1.0f;
|
||||
vertices[i].u = mVertexBuffer[frame1 + i].u;
|
||||
vertices[i].v = mVertexBuffer[frame1 + i].v;
|
||||
}
|
||||
|
||||
polyrenderer->VertexBuffer = vertices;
|
||||
polyrenderer->IndexBuffer = &mIndexBuffer[0];
|
||||
}
|
||||
}
|
||||
}
|
100
src/swrenderer/things/r_model.h
Normal file
100
src/swrenderer/things/r_model.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
** 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 "polyrenderer/drawers/poly_triangle.h"
|
||||
#include "r_data/matrix.h"
|
||||
#include "r_data/models/models.h"
|
||||
#include "swrenderer/r_renderthread.h"
|
||||
#include "swrenderer/things/r_visiblesprite.h"
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
void RenderHUDModel(RenderThread *thread, DPSprite *psp, float ofsx, float ofsy);
|
||||
|
||||
class RenderModel : public VisibleSprite
|
||||
{
|
||||
public:
|
||||
RenderModel(float x, float y, float z, FSpriteModelFrame *smf, AActor *actor, float idepth);
|
||||
|
||||
static void Project(RenderThread *thread, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor);
|
||||
|
||||
protected:
|
||||
void Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ) override;
|
||||
bool IsModel() const override { return true; }
|
||||
|
||||
private:
|
||||
float x, y, z;
|
||||
FSpriteModelFrame *smf;
|
||||
AActor *actor;
|
||||
};
|
||||
|
||||
class SWModelRenderer : public FModelRenderer
|
||||
{
|
||||
public:
|
||||
SWModelRenderer(RenderThread *thread);
|
||||
|
||||
void BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix) override;
|
||||
void EndDrawModel(AActor *actor, FSpriteModelFrame *smf) override;
|
||||
IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) override;
|
||||
void SetVertexBuffer(IModelVertexBuffer *buffer) override;
|
||||
void ResetVertexBuffer() override;
|
||||
VSMatrix GetViewToWorldMatrix() override;
|
||||
void BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix) override;
|
||||
void EndDrawHUDModel(AActor *actor) override;
|
||||
void SetInterpolation(double interpolation) override;
|
||||
void SetMaterial(FTexture *skin, bool clampNoFilter, int translation) override;
|
||||
void DrawArrays(int start, int count) override;
|
||||
void DrawElements(int numIndices, size_t offset) override;
|
||||
double GetTimeFloat() override;
|
||||
|
||||
RenderThread *Thread = nullptr;
|
||||
|
||||
AActor *ModelActor = nullptr;
|
||||
TriMatrix ObjectToWorld;
|
||||
FTexture *SkinTexture = nullptr;
|
||||
unsigned int *IndexBuffer = nullptr;
|
||||
TriVertex *VertexBuffer = nullptr;
|
||||
float InterpolationFactor = 0.0;
|
||||
};
|
||||
|
||||
class SWModelVertexBuffer : public IModelVertexBuffer
|
||||
{
|
||||
public:
|
||||
SWModelVertexBuffer(bool needindex, bool singleframe);
|
||||
~SWModelVertexBuffer();
|
||||
|
||||
FModelVertex *LockVertexBuffer(unsigned int size) override;
|
||||
void UnlockVertexBuffer() override;
|
||||
|
||||
unsigned int *LockIndexBuffer(unsigned int size) override;
|
||||
void UnlockIndexBuffer() override;
|
||||
|
||||
void SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size) override;
|
||||
|
||||
private:
|
||||
int mIndexFrame[2];
|
||||
TArray<FModelVertex> mVertexBuffer;
|
||||
TArray<unsigned int> mIndexBuffer;
|
||||
};
|
||||
}
|
|
@ -95,6 +95,9 @@ namespace swrenderer
|
|||
(r_deathcamera && Thread->Viewport->viewpoint.camera->health <= 0))
|
||||
return;
|
||||
|
||||
if (r_models && gl_IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player))
|
||||
renderHUDModel = true;
|
||||
|
||||
FDynamicColormap *basecolormap;
|
||||
CameraLight *cameraLight = CameraLight::Instance();
|
||||
if (cameraLight->FixedLightLevel() < 0 && Thread->Viewport->viewpoint.sector->e && Thread->Viewport->viewpoint.sector->e->XFloor.lightlist.Size())
|
||||
|
@ -250,6 +253,12 @@ namespace swrenderer
|
|||
sy += wy;
|
||||
}
|
||||
|
||||
if (renderHUDModel)
|
||||
{
|
||||
RenderHUDModel(Thread, pspr, (float)sx, (float)sy);
|
||||
return;
|
||||
}
|
||||
|
||||
auto viewport = Thread->Viewport.get();
|
||||
|
||||
double pspritexscale = viewport->viewwindow.centerxwide / 160.0;
|
||||
|
|
|
@ -97,5 +97,6 @@ namespace swrenderer
|
|||
|
||||
TArray<HWAccelPlayerSprite> AcceleratedSprites;
|
||||
sector_t tempsec;
|
||||
bool renderHUDModel = false;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -51,6 +51,12 @@ namespace swrenderer
|
|||
{
|
||||
void VisibleSprite::Render(RenderThread *thread)
|
||||
{
|
||||
if (IsModel())
|
||||
{
|
||||
Render(thread, nullptr, nullptr, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
short *clipbot = thread->clipbot;
|
||||
short *cliptop = thread->cliptop;
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ namespace swrenderer
|
|||
virtual bool IsParticle() const { return false; }
|
||||
virtual bool IsVoxel() const { return false; }
|
||||
virtual bool IsWallSprite() const { return false; }
|
||||
virtual bool IsModel() const { return false; }
|
||||
|
||||
virtual void Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ) = 0;
|
||||
|
||||
|
|
|
@ -25,6 +25,11 @@
|
|||
|
||||
namespace swrenderer
|
||||
{
|
||||
void SkyDrawerArgs::DrawDepthSkyColumn(RenderThread *thread, float idepth)
|
||||
{
|
||||
thread->Drawers(dc_viewport)->DrawDepthSkyColumn(*this, idepth);
|
||||
}
|
||||
|
||||
void SkyDrawerArgs::DrawSingleSkyColumn(RenderThread *thread)
|
||||
{
|
||||
thread->Drawers(dc_viewport)->DrawSingleSkyColumn(*this);
|
||||
|
|
|
@ -41,6 +41,7 @@ namespace swrenderer
|
|||
|
||||
RenderViewport *Viewport() const { return dc_viewport; }
|
||||
|
||||
void DrawDepthSkyColumn(RenderThread *thread, float idepth);
|
||||
void DrawSingleSkyColumn(RenderThread *thread);
|
||||
void DrawDoubleSkyColumn(RenderThread *thread);
|
||||
|
||||
|
|
|
@ -107,6 +107,11 @@ namespace swrenderer
|
|||
}
|
||||
}
|
||||
|
||||
void SpanDrawerArgs::DrawDepthSpan(RenderThread *thread, float idepth)
|
||||
{
|
||||
thread->Drawers(ds_viewport)->DrawDepthSpan(*this, idepth);
|
||||
}
|
||||
|
||||
void SpanDrawerArgs::DrawSpan(RenderThread *thread)
|
||||
{
|
||||
(thread->Drawers(ds_viewport)->*spanfunc)(*this);
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace swrenderer
|
|||
void SetTextureVStep(double vstep) { ds_ystep = (uint32_t)(int64_t)(vstep * 4294967296.0); }
|
||||
void SetSolidColor(int colorIndex) { ds_color = colorIndex; }
|
||||
|
||||
void DrawDepthSpan(RenderThread *thread, float idepth);
|
||||
void DrawSpan(RenderThread *thread);
|
||||
void DrawTiltedSpan(RenderThread *thread, int y, int x1, int x2, const FVector3 &plane_sz, const FVector3 &plane_su, const FVector3 &plane_sv, bool plane_shade, int planeshade, float planelightfloat, fixed_t pviewx, fixed_t pviewy, FDynamicColormap *basecolormap);
|
||||
void DrawColoredSpan(RenderThread *thread, int y, int x1, int x2);
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
CVAR(String, r_viewsize, "", CVAR_NOSET)
|
||||
|
||||
EXTERN_CVAR(Float, r_visibility);
|
||||
EXTERN_CVAR(Int, screenblocks)
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
|
@ -58,6 +59,17 @@ namespace swrenderer
|
|||
{
|
||||
}
|
||||
|
||||
void RenderViewport::SetupPolyViewport()
|
||||
{
|
||||
PolyStencilBuffer::Instance()->Clear(RenderTarget->GetWidth(), RenderTarget->GetHeight(), 0);
|
||||
PolyZBuffer::Instance()->Resize(RenderTarget->GetPitch(), RenderTarget->GetHeight());
|
||||
|
||||
PolyTriangleDrawer::set_viewport(viewwindowx, viewwindowy, viewwidth, viewheight, RenderTarget);
|
||||
WorldToView = TriMatrix::worldToView(viewpoint);
|
||||
ViewToClip = TriMatrix::viewToClip(viewwindow.FocalTangent, CenterY, YaspectMul);
|
||||
WorldToClip = ViewToClip * WorldToView;
|
||||
}
|
||||
|
||||
void RenderViewport::SetViewport(RenderThread *thread, int fullWidth, int fullHeight, float trueratio)
|
||||
{
|
||||
int virtheight, virtwidth, virtwidth2, virtheight2;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <memory>
|
||||
#include "v_video.h"
|
||||
#include "r_defs.h"
|
||||
#include "polyrenderer/math/tri_matrix.h"
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
|
@ -19,6 +20,12 @@ namespace swrenderer
|
|||
void SetViewport(RenderThread *thread, int width, int height, float trueratio);
|
||||
void SetupFreelook();
|
||||
|
||||
void SetupPolyViewport();
|
||||
|
||||
TriMatrix WorldToView;
|
||||
TriMatrix ViewToClip;
|
||||
TriMatrix WorldToClip;
|
||||
|
||||
DCanvas *RenderTarget = nullptr;
|
||||
|
||||
FViewWindow viewwindow;
|
||||
|
|
|
@ -32,6 +32,11 @@ namespace swrenderer
|
|||
dc_dest_y = y;
|
||||
}
|
||||
|
||||
void WallDrawerArgs::DrawDepthColumn(RenderThread *thread, float idepth)
|
||||
{
|
||||
thread->Drawers(dc_viewport)->DrawDepthWallColumn(*this, idepth);
|
||||
}
|
||||
|
||||
void WallDrawerArgs::DrawColumn(RenderThread *thread)
|
||||
{
|
||||
(thread->Drawers(dc_viewport)->*wallfunc)(*this);
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace swrenderer
|
|||
|
||||
bool IsMaskedDrawer() const;
|
||||
|
||||
void DrawDepthColumn(RenderThread *thread, float idepth);
|
||||
void DrawColumn(RenderThread *thread);
|
||||
|
||||
uint8_t *Dest() const { return dc_dest; }
|
||||
|
|
|
@ -306,15 +306,16 @@ int FTextureManager::CountBuildTiles ()
|
|||
FString artpath = rffpath;
|
||||
artpath += artfile;
|
||||
|
||||
FILE *f = fopen (artpath, "rb");
|
||||
if (f == NULL)
|
||||
FileReader fr;
|
||||
|
||||
if (!fr.Open(artpath))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
size_t len = Q_filelength (f);
|
||||
long len = fr.GetLength();
|
||||
uint8_t *art = new uint8_t[len];
|
||||
if (fread (art, 1, len, f) != len || (numtiles = CountTiles(art)) == 0)
|
||||
if (fr.Read (art, len) != len || (numtiles = CountTiles(art)) == 0)
|
||||
{
|
||||
delete[] art;
|
||||
}
|
||||
|
@ -323,7 +324,6 @@ int FTextureManager::CountBuildTiles ()
|
|||
BuildTileFiles.Push (art);
|
||||
totaltiles += numtiles;
|
||||
}
|
||||
fclose (f);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -67,23 +67,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
/* ADDED IN v2.0 */
|
||||
|
||||
/*
|
||||
* NAME
|
||||
* tmpfileplus_f - create a unique temporary file with filename stored in a fixed-length buffer
|
||||
*
|
||||
* SYNOPSIS
|
||||
* FILE *tmpfileplus_f(const char *dir, const char *prefix, char *pathnamebuf, size_t pathsize, int keep);
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Same as tmpfileplus() except receives filename in a fixed-length buffer. No allocated memory to free.
|
||||
|
||||
* ERRORS
|
||||
* E2BIG Resulting filename is too big for the buffer `pathnamebuf`.
|
||||
|
||||
*/
|
||||
|
||||
#include "tmpfileplus.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -112,75 +95,38 @@
|
|||
#define FDOPEN_ fdopen
|
||||
#endif
|
||||
|
||||
#include "m_random.h"
|
||||
#include "cmdlib.h"
|
||||
#include "zstring.h"
|
||||
|
||||
/* DEBUGGING STUFF */
|
||||
#if defined(_DEBUG) && defined(SHOW_DPRINTF)
|
||||
#define DPRINTF1(s, a1) printf(s, a1)
|
||||
#else
|
||||
#define DPRINTF1(s, a1)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define FILE_SEPARATOR "\\"
|
||||
#else
|
||||
#define FILE_SEPARATOR "/"
|
||||
#endif
|
||||
|
||||
#define RANDCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
#define NRANDCHARS (sizeof(RANDCHARS) - 1)
|
||||
|
||||
static FRandom pr_tmpfile;
|
||||
|
||||
/** Replace each byte in string s with a random character from TEMPCHARS */
|
||||
static char *set_randpart(char *s)
|
||||
{
|
||||
size_t i;
|
||||
unsigned int r;
|
||||
static unsigned int seed; /* NB static */
|
||||
|
||||
if (seed == 0)
|
||||
{ /* First time set our seed using current time and clock */
|
||||
seed = ((unsigned)time(NULL)<<8) ^ (unsigned)clock();
|
||||
}
|
||||
srand(seed++);
|
||||
|
||||
for (i = 0; i < strlen(s); i++)
|
||||
{
|
||||
r = rand() % NRANDCHARS;
|
||||
r = pr_tmpfile() % NRANDCHARS;
|
||||
s[i] = (RANDCHARS)[r];
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/** Return 1 if path is a valid directory otherwise 0 */
|
||||
static int is_valid_dir(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
if ((stat(path, &st) == 0) && (st.st_mode & S_IFDIR))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Call getenv and save a copy in buf */
|
||||
static char *getenv_save(const char *varname, char *buf, size_t bufsize)
|
||||
{
|
||||
char *ptr = getenv(varname);
|
||||
buf[0] = '\0';
|
||||
if (ptr)
|
||||
{
|
||||
strncpy(buf, ptr, bufsize);
|
||||
buf[bufsize-1] = '\0';
|
||||
return buf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try and create a randomly-named file in directory `tmpdir`.
|
||||
* If successful, allocate memory and set `tmpname_ptr` to full filepath, and return file pointer;
|
||||
* otherwise return NULL.
|
||||
* If `keep` is zero then create the file as temporary and it should not exist once closed.
|
||||
*/
|
||||
static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmpname_ptr, int keep)
|
||||
static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, FString *tmpname_ptr, int keep)
|
||||
/* PRE:
|
||||
* pfx is not NULL and points to a valid null-terminated string
|
||||
* tmpname_ptr is not NULL.
|
||||
|
@ -189,9 +135,7 @@ static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmp
|
|||
FILE *fp;
|
||||
int fd;
|
||||
char randpart[] = "1234567890";
|
||||
size_t lentempname;
|
||||
int i;
|
||||
char *tmpname = NULL;
|
||||
int oflag, pmode;
|
||||
|
||||
/* In Windows, we use the _O_TEMPORARY flag with `open` to ensure the file is deleted when closed.
|
||||
|
@ -210,28 +154,20 @@ static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmp
|
|||
pmode = S_IRUSR|S_IWUSR;
|
||||
#endif
|
||||
|
||||
if (!tmpdir || !is_valid_dir(tmpdir)) {
|
||||
if (!tmpdir || !DirExists(tmpdir)) {
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lentempname = strlen(tmpdir) + strlen(FILE_SEPARATOR) + strlen(pfx) + strlen(randpart);
|
||||
DPRINTF1("lentempname=%d\n", lentempname);
|
||||
tmpname = malloc(lentempname + 1);
|
||||
if (!tmpname)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
FString tempname;
|
||||
|
||||
/* If we don't manage to create a file after 10 goes, there is something wrong... */
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
sprintf(tmpname, "%s%s%s%s", tmpdir, FILE_SEPARATOR, pfx, set_randpart(randpart));
|
||||
DPRINTF1("[%s]\n", tmpname);
|
||||
fd = OPEN_(tmpname, oflag, pmode);
|
||||
tempname.Format("%s/%s%s", tmpdir, pfx, set_randpart(randpart));
|
||||
fd = OPEN_(tempname, oflag, pmode);
|
||||
if (fd != -1) break;
|
||||
}
|
||||
DPRINTF1("strlen(tmpname)=%d\n", strlen(tmpname));
|
||||
if (fd != -1)
|
||||
{ /* Success, so return user a proper ANSI C file pointer */
|
||||
fp = FDOPEN_(fd, "w+b");
|
||||
|
@ -247,13 +183,8 @@ static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmp
|
|||
{ /* We failed */
|
||||
fp = NULL;
|
||||
}
|
||||
if (!fp)
|
||||
{
|
||||
free(tmpname);
|
||||
tmpname = NULL;
|
||||
}
|
||||
|
||||
*tmpname_ptr = tmpname;
|
||||
if (tmpname_ptr) *tmpname_ptr = tempname;
|
||||
return fp;
|
||||
}
|
||||
|
||||
|
@ -261,77 +192,10 @@ static FILE *mktempfile_internal(const char *tmpdir, const char *pfx, char **tmp
|
|||
/* EXPORTED FUNCTIONS */
|
||||
/**********************/
|
||||
|
||||
FILE *tmpfileplus(const char *dir, const char *prefix, char **pathname, int keep)
|
||||
FILE *tmpfileplus(const char *dir, const char *prefix, FString *pathname, int keep)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
char *tmpname = NULL;
|
||||
char *tmpdir = NULL;
|
||||
const char *pfx = (prefix ? prefix : "tmp.");
|
||||
char *tempdirs[12] = { 0 };
|
||||
char env1[FILENAME_MAX+1] = { 0 };
|
||||
char env2[FILENAME_MAX+1] = { 0 };
|
||||
char env3[FILENAME_MAX+1] = { 0 };
|
||||
int ntempdirs = 0;
|
||||
int i;
|
||||
|
||||
/* Set up a list of temp directories we will try in order */
|
||||
i = 0;
|
||||
tempdirs[i++] = (char *)dir;
|
||||
#ifdef _WIN32
|
||||
tempdirs[i++] = getenv_save("TMP", env1, sizeof(env1));
|
||||
tempdirs[i++] = getenv_save("TEMP", env2, sizeof(env2));
|
||||
#else
|
||||
tempdirs[i++] = getenv_save("TMPDIR", env3, sizeof(env3));
|
||||
tempdirs[i++] = P_tmpdir;
|
||||
#endif
|
||||
tempdirs[i++] = ".";
|
||||
ntempdirs = i;
|
||||
|
||||
errno = 0;
|
||||
|
||||
/* Work through list we set up before, and break once we are successful */
|
||||
for (i = 0; i < ntempdirs; i++)
|
||||
{
|
||||
tmpdir = tempdirs[i];
|
||||
DPRINTF1("Trying tmpdir=[%s]\n", tmpdir);
|
||||
fp = mktempfile_internal(tmpdir, pfx, &tmpname, keep);
|
||||
if (fp) break;
|
||||
}
|
||||
/* If we succeeded and the user passed a pointer, set it to the alloc'd pathname: the user must free this */
|
||||
if (fp && pathname)
|
||||
*pathname = tmpname;
|
||||
else /* Otherwise, free the alloc'd memory */
|
||||
free(tmpname);
|
||||
|
||||
FILE *fp = mktempfile_internal(dir, (prefix ? prefix : "tmp."), pathname, keep);
|
||||
if (!fp && pathname) *pathname = "";
|
||||
return fp;
|
||||
}
|
||||
|
||||
/* Same as tmpfileplus() but with fixed length buffer for output filename and no memory allocation */
|
||||
FILE *tmpfileplus_f(const char *dir, const char *prefix, char *pathnamebuf, size_t pathsize, int keep)
|
||||
{
|
||||
char *tmpbuf = NULL;
|
||||
FILE *fp;
|
||||
|
||||
/* If no buffer provided, do the normal way */
|
||||
if (!pathnamebuf || (int)pathsize <= 0) {
|
||||
return tmpfileplus(dir, prefix, NULL, keep);
|
||||
}
|
||||
/* Call with a temporary buffer */
|
||||
fp = tmpfileplus(dir, prefix, &tmpbuf, keep);
|
||||
if (fp && strlen(tmpbuf) > pathsize - 1) {
|
||||
/* Succeeded but not enough room in output buffer, so clean up and return an error */
|
||||
pathnamebuf[0] = 0;
|
||||
fclose(fp);
|
||||
if (keep) remove(tmpbuf);
|
||||
free(tmpbuf);
|
||||
errno = E2BIG;
|
||||
return NULL;
|
||||
}
|
||||
/* Copy name into buffer */
|
||||
strcpy(pathnamebuf, tmpbuf);
|
||||
free(tmpbuf);
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
|
|
@ -23,9 +23,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
class FString;
|
||||
|
||||
/** Create a unique temporary file.
|
||||
@param dir (optional) directory to create file. If NULL use default TMP directory.
|
||||
|
@ -37,25 +35,9 @@ extern "C" {
|
|||
@return Pointer to stream opened in binary read/write (w+b) mode, or a null pointer on error.
|
||||
@exception ENOMEM Not enough memory to allocate filename.
|
||||
*/
|
||||
FILE *tmpfileplus(const char *dir, const char *prefix, char **pathname, int keep);
|
||||
FILE *tmpfileplus(const char *dir, const char *prefix, FString *pathname, int keep);
|
||||
|
||||
|
||||
/** Create a unique temporary file with filename stored in a fixed-length buffer.
|
||||
@param dir (optional) directory to create file. If NULL use default directory.
|
||||
@param prefix (optional) prefix for file name. If NULL use "tmp.".
|
||||
@param pathnamebuf (optional) buffer to receive full pathname of temporary file. Ignored if NULL.
|
||||
@param pathsize Size of buffer to receive filename and its terminating null character.
|
||||
@param keep If `keep` is nonzero and `pathname` is not NULL, then keep the file after closing.
|
||||
Otherwise file is automatically deleted when closed.
|
||||
@return Pointer to stream opened in binary read/write (w+b) mode, or a null pointer on error.
|
||||
@exception E2BIG Resulting filename is too big for the buffer `pathnamebuf`.
|
||||
*/
|
||||
FILE *tmpfileplus_f(const char *dir, const char *prefix, char *pathnamebuf, size_t pathsize, int keep);
|
||||
|
||||
#define TMPFILE_KEEP 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* end TMPFILEPLUS_H_ */
|
||||
|
|
|
@ -890,9 +890,10 @@ int FFont::StringWidth(const uint8_t *string) const
|
|||
|
||||
while (*string)
|
||||
{
|
||||
if (*string == TEXTCOLOR_ESCAPE)
|
||||
auto chr = GetCharFromString(string);
|
||||
if (chr == TEXTCOLOR_ESCAPE)
|
||||
{
|
||||
++string;
|
||||
// We do not need to check for UTF-8 in here.
|
||||
if (*string == '[')
|
||||
{
|
||||
while (*string != '\0' && *string != ']')
|
||||
|
@ -906,16 +907,15 @@ int FFont::StringWidth(const uint8_t *string) const
|
|||
}
|
||||
continue;
|
||||
}
|
||||
else if (*string == '\n')
|
||||
else if (chr == '\n')
|
||||
{
|
||||
if (w > maxw)
|
||||
maxw = w;
|
||||
w = 0;
|
||||
++string;
|
||||
}
|
||||
else
|
||||
{
|
||||
w += GetCharWidth(*string++) + GlobalKerning;
|
||||
w += GetCharWidth(chr) + GlobalKerning;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,78 @@
|
|||
|
||||
int ListGetInt(VMVa_List &tags);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// reads one character from the string.
|
||||
// This can handle both ISO 8859-1 and UTF-8, as well as mixed strings
|
||||
// between both encodings, which may happen if inconsistent encoding is
|
||||
// used between different files in a mod.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int GetCharFromString(const uint8_t *&string)
|
||||
{
|
||||
int z, y, x;
|
||||
|
||||
z = *string++;
|
||||
|
||||
if (z < 192)
|
||||
{
|
||||
return z;
|
||||
}
|
||||
else if (z <= 223)
|
||||
{
|
||||
y = *string++;
|
||||
if (y < 128 || y >= 192)
|
||||
{
|
||||
// not an UTF-8 sequence so return the first byte unchanged
|
||||
string--;
|
||||
}
|
||||
else
|
||||
{
|
||||
z = (z - 192) * 64 + (y - 128);
|
||||
}
|
||||
}
|
||||
else if (z >= 224 && z <= 239)
|
||||
{
|
||||
y = *string++;
|
||||
if (y < 128 || y >= 192)
|
||||
{
|
||||
// not an UTF-8 sequence so return the first byte unchanged
|
||||
string--;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = *string++;
|
||||
if (x < 128 || x >= 192)
|
||||
{
|
||||
// not an UTF-8 sequence so return the first byte unchanged
|
||||
string -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
z = (z - 224) * 4096 + (y - 128) * 64 + (x - 128);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (z >= 240)
|
||||
{
|
||||
y = *string++;
|
||||
if (y < 128 || y >= 192)
|
||||
{
|
||||
// not an UTF-8 sequence so return the first byte unchanged
|
||||
string--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we do not support 4-Byte UTF-8 here
|
||||
string += 2;
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DrawChar
|
||||
|
@ -170,7 +242,7 @@ void DCanvas::DrawTextCommon(FFont *font, int normalcolor, double x, double y, c
|
|||
|
||||
while ((const char *)ch - string < parms.maxstrlen)
|
||||
{
|
||||
c = *ch++;
|
||||
c = GetCharFromString(ch);
|
||||
if (!c)
|
||||
break;
|
||||
|
||||
|
@ -288,7 +360,7 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const uint8_t *string, bo
|
|||
|
||||
w = 0;
|
||||
|
||||
while ( (c = *string++) )
|
||||
while ( (c = GetCharFromString(string)) )
|
||||
{
|
||||
if (c == TEXTCOLOR_ESCAPE)
|
||||
{
|
||||
|
|
|
@ -86,4 +86,6 @@ inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const char *str, b
|
|||
inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const FString &str, bool preservecolor = false, unsigned int *count = nullptr)
|
||||
{ return V_BreakLines (font, maxwidth, (const uint8_t *)str.GetChars(), preservecolor, count); }
|
||||
|
||||
int GetCharFromString(const uint8_t *&string);
|
||||
|
||||
#endif //__V_TEXT_H__
|
||||
|
|
|
@ -880,7 +880,7 @@ void DFrameBuffer::DrawRateStuff ()
|
|||
|
||||
int textScale = active_con_scale();
|
||||
|
||||
chars = mysnprintf (fpsbuff, countof(fpsbuff), "%2u ms (%3u fps)", howlong, LastCount);
|
||||
chars = mysnprintf (fpsbuff, countof(fpsbuff), "%2" PRIu64 " ms (%3" PRIu64 " fps)", howlong, LastCount);
|
||||
rate_x = Width / textScale - ConFont->StringWidth(&fpsbuff[0]);
|
||||
Clear (rate_x * textScale, 0, Width, ConFont->GetHeight() * textScale, GPalette.BlackIndex, 0);
|
||||
DrawText (ConFont, CR_WHITE, rate_x, 0, (char *)&fpsbuff[0],
|
||||
|
|
|
@ -233,14 +233,12 @@ void FWadCollection::AddFile (const char *filename, FileReader *wadinfo)
|
|||
if (wadinfo == NULL)
|
||||
{
|
||||
// Does this exist? If so, is it a directory?
|
||||
struct stat info;
|
||||
if (stat(filename, &info) != 0)
|
||||
if (!DirEntryExists(filename, &isdir))
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "Could not stat %s\n", filename);
|
||||
Printf(TEXTCOLOR_RED "%s: File or Directory not found\n", filename);
|
||||
PrintLastError();
|
||||
return;
|
||||
}
|
||||
isdir = (info.st_mode & S_IFDIR) != 0;
|
||||
|
||||
if (!isdir)
|
||||
{
|
||||
|
@ -1554,7 +1552,7 @@ FWadLump::FWadLump(int lumpnum, FResourceLump *lump)
|
|||
// Uncompressed lump in a file. For this we will have to open a new FILE, since we need it for streaming
|
||||
int fileno = Wads.GetLumpFile(lumpnum);
|
||||
const char *filename = Wads.GetWadFullName(fileno);
|
||||
File = fopen(filename, "rb");
|
||||
File = openfd(filename);
|
||||
if (File != NULL)
|
||||
{
|
||||
Length = lump->LumpSize;
|
||||
|
|
|
@ -153,6 +153,33 @@ bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create
|
|||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetAppDataPath Windows
|
||||
//
|
||||
// Returns the path for the AppData folder.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetAppDataPath(bool create)
|
||||
{
|
||||
FString path;
|
||||
|
||||
if (!GetKnownFolder(CSIDL_LOCAL_APPDATA, FOLDERID_LocalAppData, create, path))
|
||||
{ // Failed (e.g. On Win9x): use program directory
|
||||
path = progdir;
|
||||
}
|
||||
// Don't use GAME_DIR and such so that ZDoom and its child ports can
|
||||
// share the node cache.
|
||||
path += "/" GAMENAMELOWERCASE;
|
||||
path.Substitute("//", "/"); // needed because progdir ends with a slash.
|
||||
if (create)
|
||||
{
|
||||
CreatePath(path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetCachePath Windows
|
||||
|
@ -173,6 +200,10 @@ FString M_GetCachePath(bool create)
|
|||
// share the node cache.
|
||||
path += "/zdoom/cache";
|
||||
path.Substitute("//", "/"); // needed because progdir ends with a slash.
|
||||
if (create)
|
||||
{
|
||||
CreatePath(path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
|
|
|
@ -380,18 +380,7 @@ enum
|
|||
BQS_InGameColormap,
|
||||
};
|
||||
|
||||
#if 0
|
||||
#define STARTLOG do { if (!dbg) dbg = fopen ("e:/vid.log", "w"); } while(0)
|
||||
#define STOPLOG do { if (dbg) { fclose (dbg); dbg=NULL; } } while(0)
|
||||
#define LOG(x) do { if (dbg) { fprintf (dbg, x); fflush (dbg); } } while(0)
|
||||
#define LOG1(x,y) do { if (dbg) { fprintf (dbg, x, y); fflush (dbg); } } while(0)
|
||||
#define LOG2(x,y,z) do { if (dbg) { fprintf (dbg, x, y, z); fflush (dbg); } } while(0)
|
||||
#define LOG3(x,y,z,zz) do { if (dbg) { fprintf (dbg, x, y, z, zz); fflush (dbg); } } while(0)
|
||||
#define LOG4(x,y,z,a,b) do { if (dbg) { fprintf (dbg, x, y, z, a, b); fflush (dbg); } } while(0)
|
||||
#define LOG5(x,y,z,a,b,c) do { if (dbg) { fprintf (dbg, x, y, z, a, b, c); fflush (dbg); } } while(0)
|
||||
extern FILE *dbg;
|
||||
#define VID_FILE_DEBUG 1
|
||||
#elif _DEBUG && 0
|
||||
#if _DEBUG && 0
|
||||
#define STARTLOG
|
||||
#define STOPLOG
|
||||
#define LOG(x) { OutputDebugString(x); }
|
||||
|
|
Loading…
Reference in a new issue