Merge branch 'master' into reverbedit

This commit is contained in:
Christoph Oelckers 2017-12-03 12:46:08 +01:00
commit 7e45535669
87 changed files with 1513 additions and 1810 deletions

View file

@ -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

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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();
}

View file

@ -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)
{

View file

@ -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());
}

View file

@ -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, ...)
{

View file

@ -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:

View file

@ -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

View file

@ -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;

View file

@ -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)

View file

@ -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)

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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);
}
}
}

View 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);
}

View file

@ -1365,6 +1365,8 @@ void ACSStringPool::ReadStrings(FSerializer &file, const char *key)
}
}
}
FindFirstFreeEntry(FirstFreeEntry);
}
//============================================================================

View file

@ -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;
}

View file

@ -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;

View file

@ -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]; }

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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

View file

@ -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 *);

View file

@ -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
{

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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]))

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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
{

View file

@ -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++)

View file

@ -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;

View file

@ -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;
}
//==========================================================================

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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)
{

View file

@ -239,7 +239,7 @@ public:
void Stop();
protected:
FILE *File;
FileWriter *File;
};
// WildMidi implementation of a MIDI device ---------------------------------

View file

@ -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());

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -94,6 +94,10 @@ namespace swrenderer
virtual void DrawTiltedSpan(const SpanDrawerArgs &args, 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) = 0;
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;
};

View file

@ -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;

View file

@ -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);
}
/////////////////////////////////////////////////////////////////////////

View file

@ -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)

View file

@ -85,7 +85,7 @@ namespace swrenderer
{
return;
}
auto viewport = Thread->Viewport.get();
drawerargs.SetSolidColor(3);
@ -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);
}
}

View file

@ -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"

View file

@ -29,6 +29,8 @@ class DrawerCommandQueue;
typedef std::shared_ptr<DrawerCommandQueue> DrawerCommandQueuePtr;
class RenderMemory;
EXTERN_CVAR(Bool, r_models);
namespace swrenderer
{
class VisibleSpriteList;

View file

@ -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);
}
}
}
}
}

View file

@ -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)

View 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];
}
}
}

View 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;
};
}

View file

@ -94,6 +94,9 @@ namespace swrenderer
(players[consoleplayer].cheats & CF_CHASECAM) ||
(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();
@ -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;

View file

@ -97,5 +97,6 @@ namespace swrenderer
TArray<HWAccelPlayerSprite> AcceleratedSprites;
sector_t tempsec;
bool renderHUDModel = false;
};
}

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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; }

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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_ */

View file

@ -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;
}
}

View file

@ -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)
{

View file

@ -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__

View file

@ -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],

View file

@ -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;

View file

@ -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;
}

View file

@ -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); }