diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1ec06da076..8610691abc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/b_game.cpp b/src/b_game.cpp index 1cb91ddf49..4300e0ada6 100644 --- a/src/b_game.cpp +++ b/src/b_game.cpp @@ -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; } diff --git a/src/cmdlib.cpp b/src/cmdlib.cpp index 3c2e7e2807..bccb4afcd6 100644 --- a/src/cmdlib.cpp +++ b/src/cmdlib.cpp @@ -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 &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; diff --git a/src/cmdlib.h b/src/cmdlib.h index e2119ed8a8..76a2798dab 100644 --- a/src/cmdlib.h +++ b/src/cmdlib.h @@ -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; diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 87f1d589e0..f68fd1d634 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -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(); } diff --git a/src/d_main.cpp b/src/d_main.cpp index 301be20f8b..9d8055b0d8 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1946,13 +1946,11 @@ static FString CheckGameInfo(TArray & 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) { diff --git a/src/d_net.cpp b/src/d_net.cpp index e8711bda50..57dbb93b74 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -26,6 +26,7 @@ //----------------------------------------------------------------------------- #include +#include #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()); } diff --git a/src/files.cpp b/src/files.cpp index 0de13e8ea8..8ad4d63294 100644 --- a/src/files.cpp +++ b/src/files.cpp @@ -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, ...) { diff --git a/src/files.h b/src/files.h index 4c73273a12..808f24d94d 100644 --- a/src/files.h +++ b/src/files.h @@ -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: diff --git a/src/g_game.cpp b/src/g_game.cpp index ec1a7be506..f56bdac8ee 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -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; diff --git a/src/gl/hqnx_asm/hqnx_asm_Image.cpp b/src/gl/hqnx_asm/hqnx_asm_Image.cpp index 7af1201739..31adda8742 100644 --- a/src/gl/hqnx_asm/hqnx_asm_Image.cpp +++ b/src/gl/hqnx_asm/hqnx_asm_Image.cpp @@ -106,1078 +106,6 @@ int DLL CImage::Convert32To17( void ) return nRes; } -int DLL CImage::ConvertTo32( void ) -{ - int nRes = eConvUnknownFormat; - if ( m_pBitmap == NULL ) - return eConvSourceMemory; - - switch ( m_BitPerPixel ) - { - case 8: - { - nRes = 0; - m_BitPerPixel = 32; - unsigned char * pNewBitmap = (unsigned char *)malloc(m_NumPixel*4); - if ( pNewBitmap != NULL ) - { - unsigned char * pTemp8 = m_pBitmap; - unsigned char * pTemp32 = pNewBitmap; - unsigned char c; - for ( int i=0; i> 3); - *(pTemp24++) = ((rgb & 0xF800) >> 8); - } - free(m_pBitmap); - m_pBitmap = pNewBitmap; - } - else - nRes = eConvDestMemory; - - break; - } - case 32: - { - nRes = 0; - m_BitPerPixel = 24; - unsigned char * pNewBitmap = (unsigned char *)malloc(m_NumPixel*3); - if ( pNewBitmap != NULL ) - { - unsigned char * pTemp32 = m_pBitmap; - unsigned char * pTemp24 = pNewBitmap; - for ( int i=0; i> 3; - g = m_Pal[c].g >> 2; - b = m_Pal[c].b >> 3; - *(pTemp16++) = (r << 11) + (g << 5) + b; - } - free(m_pBitmap); - m_pBitmap = pNewBitmap; - } - else - nRes = eConvDestMemory; - - break; - } - case 24: - { - nRes = 0; - m_BitPerPixel = 16; - unsigned char * pNewBitmap = (unsigned char *)malloc(m_NumPixel*2); - if ( pNewBitmap != NULL ) - { - unsigned char * pTemp24 = m_pBitmap; - unsigned short * pTemp16 = (unsigned short *)pNewBitmap; - unsigned short r, g, b; - for ( int i=0; i> 3; - g = (*(pTemp24++)) >> 2; - r = (*(pTemp24++)) >> 3; - *(pTemp16++) = (r << 11) + (g << 5) + b; - } - free(m_pBitmap); - m_pBitmap = pNewBitmap; - } - else - nRes = eConvDestMemory; - - break; - } - case 32: - { - nRes = 0; - m_BitPerPixel = 16; - unsigned char * pNewBitmap = (unsigned char *)malloc(m_NumPixel*2); - if ( pNewBitmap != NULL ) - { - unsigned char * pTemp32 = m_pBitmap; - unsigned short * pTemp16 = (unsigned short *)pNewBitmap; - unsigned short r, g, b; - for ( int i=0; i> 3; - g = (*(pTemp32++)) >> 2; - r = (*(pTemp32++)) >> 3; - pTemp32++; - *(pTemp16++) = (r << 11) + (g << 5) + b; - } - free(m_pBitmap); - m_pBitmap = pNewBitmap; - } - else - nRes = eConvDestMemory; - - break; - } - } - - return nRes; -} - -int CImage::Convert8To17( int transindex ) -{ - int nRes = eConvUnknownFormat; - - if ( m_BitPerPixel == 8 ) - { - m_BitPerPixel = 32; - unsigned char * pNewBitmap = (unsigned char *)malloc(m_NumPixel*4); - if ( pNewBitmap != NULL ) - { - unsigned char * pTemp8 = m_pBitmap; - unsigned int * pTemp32 = (unsigned int *)pNewBitmap; - unsigned int r, g, b; - unsigned char c; - for ( int i=0; i> 3; - g = m_Pal[c].g >> 2; - b = m_Pal[c].b >> 3; - *(pTemp32++) = (r << 11) + (g << 5) + b + (transindex != c ? 0x10000 : 0); - } - free(m_pBitmap); - m_pBitmap = pNewBitmap; - } - else - nRes = eConvDestMemory; - - nRes = 0; - } - - return nRes; -} - -int CImage::SaveBmp(char *szFilename) -{ - _BMPFILEHEADER fh; - _BMPIMAGEHEADER ih; - unsigned char BmpPal[256][4]; - long int SuffLen; - long int Dummy = 0; - unsigned char * pBuf; - short i; - - if (!(f = fopen(szFilename, "wb"))) return eSaveBmpFileOpen; - if ( m_pBitmap == NULL ) return eSaveBmpSourceMemory; - - fh.bfType=0x4D42; - if (m_BitPerPixel==8) - { - SuffLen=((m_Xres+3)/4)*4-m_Xres; - ih.biSize=0x28; - ih.biWidth=m_Xres; - ih.biHeight=m_Yres; - ih.biPlanes=1; - ih.biBitCount=8; - ih.biCompression=0; - ih.biSizeImage=(m_Xres+SuffLen)*m_Yres; - ih.biXPelsPerMeter=ih.biYPelsPerMeter=0x2E23; // 300dpi (pixels per meter) - ih.biClrUsed=ih.biClrImportant=0; - fh.bfSize=(ih.biSizeImage)+0x0436; - fh.bfRes1=0; - fh.bfOffBits=0x0436; - if (fwrite(&fh, 14, 1, f) != 1) return eSaveBmpFileWrite; - if (fwrite(&ih, 40, 1, f) != 1) return eSaveBmpFileWrite; - for (i=0; i<256; i++) - { - BmpPal[i][0]=m_Pal[i].b; - BmpPal[i][1]=m_Pal[i].g; - BmpPal[i][2]=m_Pal[i].r; - BmpPal[i][3]=0; - } - if (fwrite(&BmpPal, 1024, 1, f) != 1) return eSaveBmpFileWrite; - pBuf=m_pBitmap; - pBuf+=m_NumPixel; - for (i=0; i0) - { - if (fwrite(&Dummy, SuffLen, 1, f) != 1) return eSaveBmpFileWrite; - } - } - } - else - if (m_BitPerPixel==24) - { - SuffLen=((m_Xres*3+3)/4)*4-m_Xres*3; - ih.biSize=0x28; - ih.biWidth=m_Xres; - ih.biHeight=m_Yres; - ih.biPlanes=1; - ih.biBitCount=24; - ih.biCompression=0; - ih.biSizeImage=(m_Xres*3+SuffLen)*m_Yres; - ih.biXPelsPerMeter=ih.biYPelsPerMeter=0x2E23; // 300dpi (pixels per meter) - ih.biClrUsed=ih.biClrImportant=0; - fh.bfSize=(ih.biSizeImage)+0x0036; - fh.bfRes1=0; - fh.bfOffBits=0x0036; - if (fwrite(&fh, 14, 1, f) != 1) return eSaveBmpFileWrite; - if (fwrite(&ih, 40, 1, f) != 1) return eSaveBmpFileWrite; - pBuf=m_pBitmap; - pBuf+=m_NumPixel*3; - for (i=0; i0) - { - if (fwrite(&Dummy, SuffLen, 1, f) != 1) return eSaveBmpFileWrite; - } - } - } - else - return eSaveBmpColorDepth; - - fclose(f); - - return 0; -} - -int CImage::LoadBmp(char *szFilename) -{ - _BMPFILEHEADER fh; - _BMPIMAGEHEADEROLD ih_old; - _BMPIMAGEHEADER ih; - unsigned char BmpPal[256][4]; - long int biSize; - long int SuffLen; - long int Dummy = 0; - unsigned char * pBuf; - short i; - long int xres, yres; - unsigned short bits; - - if (!(f = fopen(szFilename, "rb"))) return eLoadBmpFileOpen; - if (fread(&fh, 14, 1, f) != 1) return eLoadBmpFileRead; - if (fh.bfType != 0x4D42) return eLoadBmpBadFormat; - if (fread(&biSize, 4, 1, f) != 1) return eLoadBmpFileRead; - if (biSize > 12) - { - fseek( f, -4, SEEK_CUR ); - if (fread(&ih, biSize, 1, f) != 1) return eLoadBmpFileRead; - xres = ih.biWidth; - yres = ih.biHeight; - bits = ih.biBitCount; - } - else - { - fseek( f, -4, SEEK_CUR ); - if (fread(&ih_old, biSize, 1, f) != 1) return eLoadBmpFileRead; - xres = ih_old.biWidth; - yres = ih_old.biHeight; - bits = ih_old.biBitCount; - } - - if ( Init( xres, yres, bits ) != 0 ) return eLoadBmpInit; - if (m_BitPerPixel==8) - { - SuffLen=((m_Xres+3)/4)*4-m_Xres; - if (fread(&BmpPal, 1024, 1, f) != 1) return eLoadBmpFileRead; - for (i=0; i<256; i++) - { - m_Pal[i].b=BmpPal[i][0]; - m_Pal[i].g=BmpPal[i][1]; - m_Pal[i].r=BmpPal[i][2]; - } - pBuf=m_pBitmap; - pBuf+=m_NumPixel; - for (i=0; i0) - { - if (fread(&Dummy, SuffLen, 1, f) != 1) return eLoadBmpFileRead; - } - } - } - else - if (m_BitPerPixel==24) - { - SuffLen=((m_Xres*3+3)/4)*4-(m_Xres*3); - pBuf=m_pBitmap; - pBuf+=m_NumPixel*3; - for (i=0; i0) - { - if (fread(&Dummy, SuffLen, 1, f) != 1) return eLoadBmpFileRead; - } - } - } - else - return eLoadBmpColorDepth; - - fclose(f); - - return 0; -} - -void CImage::Output( void ) -{ - fwrite(m_cBuf, m_nCount, 1, f); - m_nCount=0; -} - -void CImage::Output( char c ) -{ - if ( m_nCount == sizeof(m_cBuf) ) - { - fwrite(m_cBuf, m_nCount, 1, f); - m_nCount=0; - } - m_cBuf[m_nCount++] = c; -} - -void CImage::Output( char * pcData, int nSize ) -{ - for ( int i=0; i 0 ) - { - Output( nDif-1 ); - Output( (char*)(pcolBuf+i-nDif-nRep), nDif ); - } - nDif = 1; - } - } - else - { - if ( bEqual && (nRep<127) ) - nRep++; - else - { - Output( nRep+128 ); - Output( (char*)&colOld, 1 ); - nRep = 0; - nDif = 1; - } - } - } - - if ( nRep == 0 ) - { - Output( nDif-1 ); - Output( (char*)(pcolBuf+m_Xres-nDif), nDif ); - } - else - { - Output( nRep+128 ); - Output( (char*)&colOld, 1 ); - } - Output(); - } - } - } - else - if (m_BitPerPixel==24) - { - fh.tiImageType = bCompressed ? 10 : 2; - if (fwrite(&fh, sizeof(fh), 1, f) != 1) return eSaveTgaFileWrite; - - _BGR * pcolBuf = (_BGR *)m_pBitmap; - pcolBuf += m_NumPixel; - - if ( !bCompressed ) - { - for (j=0; j 0 ) - { - Output( nDif-1 ); - Output( (char*)(pcolBuf+i-nDif-nRep), sizeof(_BGR)*nDif ); - } - nDif = 1; - } - } - else - { - if ( bEqual && (nRep<127) ) - nRep++; - else - { - Output( nRep+128 ); - Output( (char*)&colOld, sizeof(_BGR) ); - nRep = 0; - nDif = 1; - } - } - } - - if ( nRep == 0 ) - { - Output( nDif-1 ); - Output( (char*)(pcolBuf+m_Xres-nDif), sizeof(_BGR)*nDif ); - } - else - { - Output( nRep+128 ); - Output( (char*)&colOld, sizeof(_BGR) ); - } - Output(); - } - } - } - else - if (m_BitPerPixel==32) - { - fh.tiImageType = bCompressed ? 10 : 2; - fh.tiAttrBits = 8; - if (fwrite(&fh, sizeof(fh), 1, f) != 1) return eSaveTgaFileWrite; - - _BGRA * pcolBuf = (_BGRA *)m_pBitmap; - pcolBuf += m_NumPixel; - - if ( !bCompressed ) - { - for (j=0; j 0 ) - { - Output( nDif-1 ); - Output( (char*)(pcolBuf+i-nDif-nRep), sizeof(_BGRA)*nDif ); - } - nDif = 1; - } - } - else - { - if ( bEqual && (nRep<127) ) - nRep++; - else - { - Output( nRep+128 ); - Output( (char*)&colOld, sizeof(_BGRA) ); - nRep = 0; - nDif = 1; - } - } - } - - if ( nRep == 0 ) - { - Output( nDif-1 ); - Output( (char*)(pcolBuf+m_Xres-nDif), sizeof(_BGRA)*nDif ); - } - else - { - Output( nRep+128 ); - Output( (char*)&colOld, sizeof(_BGRA) ); - } - Output(); - } - } - } - else - return eSaveTgaColorDepth; - - fclose(f); - - return 0; -} - -int CImage::LoadTga(char *szFilename) -{ - _TGAHEADER fh; - int i, j, k; - unsigned char nCount; - - if (!(f = fopen(szFilename, "rb"))) return eLoadTgaFileOpen; - if (fread(&fh, sizeof(fh), 1, f) != 1) return eLoadTgaFileRead; - bool bCompressed = (( fh.tiImageType & 8 ) != 0); - if ((fh.tiBitPerPixel<=0) || (fh.tiBitPerPixel>32)) - return eLoadTgaBadFormat; - - if ( Init( fh.tiXres, fh.tiYres, fh.tiBitPerPixel ) != 0 ) - return eLoadTgaInit; - - if ( m_BitPerPixel == 8 ) - { - if ( fh.tiPaletteIncluded == 1 ) - { - if ( fh.tiPaletteBpp == 24) - { - if (fread(&m_Pal, 3, fh.tiPaletteSize, f) != fh.tiPaletteSize) - return eLoadTgaFileRead; - } - else - if ( fh.tiPaletteBpp == 32) - { - unsigned char BmpPal[256][4]; - - if (fread(&BmpPal, 4, fh.tiPaletteSize, f) != fh.tiPaletteSize) - return eLoadTgaFileRead; - - for (i=0; i= m_pBitmap ) - { - nCount = Input(); - if ((nCount & 128)==0) - { - for (k=0; k<=nCount; k++) - { - colCur = Input(); - *(pcolBuf+i) = colCur; - if ( (++i) == m_Xres ) - { - i=0; - pcolBuf -= m_Xres; - break; - } - } - } - else - { - colCur = Input(); - for (k=0; k<=nCount-128; k++) - { - *(pcolBuf+i) = colCur; - if ( (++i) == m_Xres ) - { - i=0; - pcolBuf -= m_Xres; - break; - } - } - } - } - } - } - else - if ( m_BitPerPixel == 24 ) - { - _BGR * pcolBuf = (_BGR *)m_pBitmap; - pcolBuf += m_NumPixel; - - if ( !bCompressed ) - { - for (j=0; j= (_BGR *)m_pBitmap ) - { - nCount = Input(); - if ((nCount & 128)==0) - { - for (k=0; k<=nCount; k++) - { - colCur.b = Input(); - colCur.g = Input(); - colCur.r = Input(); - *(pcolBuf+i) = colCur; - if ( (++i) == m_Xres ) - { - i=0; - pcolBuf -= m_Xres; - break; - } - } - } - else - { - colCur.b = Input(); - colCur.g = Input(); - colCur.r = Input(); - for (k=0; k<=nCount-128; k++) - { - *(pcolBuf+i) = colCur; - if ( (++i) == m_Xres ) - { - i=0; - pcolBuf -= m_Xres; - break; - } - } - } - } - } - } - else - if ( m_BitPerPixel == 32 ) - { - _BGRA * pcolBuf = (_BGRA *)m_pBitmap; - pcolBuf += m_NumPixel; - - if ( !bCompressed ) - { - for (j=0; j= (_BGRA *)m_pBitmap ) - { - nCount = Input(); - if ((nCount & 128)==0) - { - for (k=0; k<=nCount; k++) - { - colCur.b = Input(); - colCur.g = Input(); - colCur.r = Input(); - colCur.a = Input(); - *(pcolBuf+i) = colCur; - if ( (++i) == m_Xres ) - { - i=0; - pcolBuf -= m_Xres; - break; - } - } - } - else - { - colCur.b = Input(); - colCur.g = Input(); - colCur.r = Input(); - colCur.a = Input(); - for (k=0; k<=nCount-128; k++) - { - *(pcolBuf+i) = colCur; - if ( (++i) == m_Xres ) - { - i=0; - pcolBuf -= m_Xres; - break; - } - } - } - } - } - } - else - return eLoadTgaColorDepth; - - fclose(f); - - return 0; -} - -int DLL CImage::Load(char *szFilename) -{ - int nRes = 0; - - if ( szFilename != NULL ) - { - char * szExt = strrchr( szFilename, '.' ); - int nNotTGA = 1; - - if ( szExt != NULL ) - nNotTGA = _stricmp( szExt, ".tga" ); - - if ( nNotTGA != 0 ) - nRes = LoadBmp( szFilename ); - else - nRes = LoadTga( szFilename ); - } - else - nRes = eLoadFilename; - - return nRes; -} - -int DLL CImage::Save(char *szFilename) -{ - int nRes = 0; - int nNotTGA = 1; - - if ( szFilename != NULL ) - { - char * szExt = strrchr( szFilename, '.' ); - - if ( szExt != NULL ) - nNotTGA = _stricmp( szExt, ".tga" ); - - if ( nNotTGA != 0 ) - { - if (( m_BitPerPixel == 16 ) || ( m_BitPerPixel == 32 )) - nRes = ConvertTo24(); - - if (nRes == 0) - nRes = SaveBmp( szFilename ); - } - else - { - if ( m_BitPerPixel == 16 ) - nRes = ConvertTo24(); - - if (nRes == 0) - nRes = SaveTga( szFilename, true ); - } - } - else - nRes = eSaveFilename; - - return nRes; -} } \ No newline at end of file diff --git a/src/gl/hqnx_asm/hqnx_asm_Image.h b/src/gl/hqnx_asm/hqnx_asm_Image.h index 38f0f1d6a9..918b904fe2 100644 --- a/src/gl/hqnx_asm/hqnx_asm_Image.h +++ b/src/gl/hqnx_asm/hqnx_asm_Image.h @@ -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; diff --git a/src/gl/utility/gl_clock.cpp b/src/gl/utility/gl_clock.cpp index df96fb6b8f..1003fae865 100644 --- a/src/gl/utility/gl_clock.cpp +++ b/src/gl/utility/gl_clock.cpp @@ -43,6 +43,8 @@ #include #endif +#include + #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) diff --git a/src/i_time.cpp b/src/i_time.cpp index bea0272432..0511a79f06 100644 --- a/src/i_time.cpp +++ b/src/i_time.cpp @@ -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(steady_clock::now().time_since_epoch()).count()) * TimeScale); + return (uint64_t)((duration_cast(steady_clock::now().time_since_epoch()).count()) * (uint64_t)(TimeScale * 1000)); } static uint64_t MSToNS(unsigned int ms) diff --git a/src/m_misc.cpp b/src/m_misc.cpp index bda8dcb806..c2fa021f6d 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -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); } } diff --git a/src/m_misc.h b/src/m_misc.h index 660eb7a587..8f375b9309 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -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); diff --git a/src/m_png.cpp b/src/m_png.cpp index 28f015e7b0..08cac8d543 100644 --- a/src/m_png.cpp +++ b/src/m_png.cpp @@ -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 diff --git a/src/m_png.h b/src/m_png.h index 70c45b7108..4182440fb9 100644 --- a/src/m_png.h +++ b/src/m_png.h @@ -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 diff --git a/src/md5.cpp b/src/md5.cpp index aa4b506daa..d345e00d61 100644 --- a/src/md5.cpp +++ b/src/md5.cpp @@ -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); } } } diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index bec3082b11..c9fb7aebaf 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -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); } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 2dfbec49b4..3d93e7a0a5 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1365,6 +1365,8 @@ void ACSStringPool::ReadStrings(FSerializer &file, const char *key) } } } + + FindFirstFreeEntry(FirstFreeEntry); } //============================================================================ diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index e1510145e3..977426e572 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -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; } diff --git a/src/polyrenderer/drawers/poly_draw_args.cpp b/src/polyrenderer/drawers/poly_draw_args.cpp index 5fb7f0288d..466a39f4ab 100644 --- a/src/polyrenderer/drawers/poly_draw_args.cpp +++ b/src/polyrenderer/drawers/poly_draw_args.cpp @@ -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(*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(*this, PolyTriangleDrawer::is_mirror()); +} + void PolyDrawArgs::DrawArray(PolyRenderThread *thread, const TriVertex *vertices, int vcount, PolyDrawMode mode) { mVertices = vertices; diff --git a/src/polyrenderer/drawers/poly_draw_args.h b/src/polyrenderer/drawers/poly_draw_args.h index 31780d77ae..eb543bbbf5 100644 --- a/src/polyrenderer/drawers/poly_draw_args.h +++ b/src/polyrenderer/drawers/poly_draw_args.h @@ -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]; } diff --git a/src/polyrenderer/drawers/poly_triangle.cpp b/src/polyrenderer/drawers/poly_triangle.cpp index 386c4c6304..990ca581db 100644 --- a/src/polyrenderer/drawers/poly_triangle.cpp +++ b/src/polyrenderer/drawers/poly_triangle.cpp @@ -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); } } diff --git a/src/polyrenderer/drawers/poly_triangle.h b/src/polyrenderer/drawers/poly_triangle.h index eea3b8531f..7ddfbed19a 100644 --- a/src/polyrenderer/drawers/poly_triangle.h +++ b/src/polyrenderer/drawers/poly_triangle.h @@ -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); diff --git a/src/polyrenderer/drawers/screen_triangle.cpp b/src/polyrenderer/drawers/screen_triangle.cpp index c0e4104fcb..37a7f843ba 100644 --- a/src/polyrenderer/drawers/screen_triangle.cpp +++ b/src/polyrenderer/drawers/screen_triangle.cpp @@ -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::Execute, // TextureOpaque diff --git a/src/polyrenderer/drawers/screen_triangle.h b/src/polyrenderer/drawers/screen_triangle.h index a76dc4b466..62f59ba448 100644 --- a/src/polyrenderer/drawers/screen_triangle.h +++ b/src/polyrenderer/drawers/screen_triangle.h @@ -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 *); diff --git a/src/polyrenderer/math/tri_matrix.cpp b/src/polyrenderer/math/tri_matrix.cpp index df0e7d4e05..ed606d7938 100644 --- a/src/polyrenderer/math/tri_matrix.cpp +++ b/src/polyrenderer/math/tri_matrix.cpp @@ -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 { diff --git a/src/polyrenderer/math/tri_matrix.h b/src/polyrenderer/math/tri_matrix.h index 908ef247d3..592825c201 100644 --- a/src/polyrenderer/math/tri_matrix.h +++ b/src/polyrenderer/math/tri_matrix.h @@ -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; diff --git a/src/polyrenderer/scene/poly_model.cpp b/src/polyrenderer/scene/poly_model.cpp index 285d19e16f..c952625c31 100644 --- a/src/polyrenderer/scene/poly_model.cpp +++ b/src/polyrenderer/scene/poly_model.cpp @@ -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; diff --git a/src/polyrenderer/scene/poly_model.h b/src/polyrenderer/scene/poly_model.h index b4896b7d8d..a064459e9f 100644 --- a/src/polyrenderer/scene/poly_model.h +++ b/src/polyrenderer/scene/poly_model.h @@ -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; diff --git a/src/polyrenderer/scene/poly_playersprite.cpp b/src/polyrenderer/scene/poly_playersprite.cpp index 017396ffb2..3c17941ba3 100644 --- a/src/polyrenderer/scene/poly_playersprite.cpp +++ b/src/polyrenderer/scene/poly_playersprite.cpp @@ -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; diff --git a/src/polyrenderer/scene/poly_sprite.cpp b/src/polyrenderer/scene/poly_sprite.cpp index 9ea184c35c..f3ce12a5e6 100644 --- a/src/polyrenderer/scene/poly_sprite.cpp +++ b/src/polyrenderer/scene/poly_sprite.cpp @@ -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])) diff --git a/src/posix/cocoa/i_system.mm b/src/posix/cocoa/i_system.mm index bb1ea2e1b9..3be9a067ce 100644 --- a/src/posix/cocoa/i_system.mm +++ b/src/posix/cocoa/i_system.mm @@ -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; diff --git a/src/posix/i_steam.cpp b/src/posix/i_steam.cpp index 9819bc09e3..f233f4ce81 100644 --- a/src/posix/i_steam.cpp +++ b/src/posix/i_steam.cpp @@ -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 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 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); } } diff --git a/src/posix/osx/i_specialpaths.mm b/src/posix/osx/i_specialpaths.mm index 843fb82d6c..fbb32cec69 100644 --- a/src/posix/osx/i_specialpaths.mm +++ b/src/posix/osx/i_specialpaths.mm @@ -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; } diff --git a/src/posix/sdl/i_system.cpp b/src/posix/sdl/i_system.cpp index 7bf23af117..b71acb8f8d 100644 --- a/src/posix/sdl/i_system.cpp +++ b/src/posix/sdl/i_system.cpp @@ -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; } diff --git a/src/posix/unix/i_specialpaths.cpp b/src/posix/unix/i_specialpaths.cpp index 5dedba0578..581fda5d50 100644 --- a/src/posix/unix/i_specialpaths.cpp +++ b/src/posix/unix/i_specialpaths.cpp @@ -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 diff --git a/src/resourcefiles/file_directory.cpp b/src/resourcefiles/file_directory.cpp index 77e5d0141e..02c70a21e3 100644 --- a/src/resourcefiles/file_directory.cpp +++ b/src/resourcefiles/file_directory.cpp @@ -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; diff --git a/src/resourcefiles/file_zip.cpp b/src/resourcefiles/file_zip.cpp index 02e350998c..3d842131d3 100644 --- a/src/resourcefiles/file_zip.cpp +++ b/src/resourcefiles/file_zip.cpp @@ -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 &filenames, TArray &filenames, TArrayTell(); 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 &filenames, TArrayTell() - 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; diff --git a/src/resourcefiles/resourcefile.cpp b/src/resourcefiles/resourcefile.cpp index 7c9c957e33..96bd50e0f5 100644 --- a/src/resourcefiles/resourcefile.cpp +++ b/src/resourcefiles/resourcefile.cpp @@ -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 { diff --git a/src/s_playlist.cpp b/src/s_playlist.cpp index e1b0fd5b61..315a2ac763 100644 --- a/src/s_playlist.cpp +++ b/src/s_playlist.cpp @@ -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++) diff --git a/src/s_playlist.h b/src/s_playlist.h index 74c06f8578..859f0bce41 100644 --- a/src/s_playlist.h +++ b/src/s_playlist.h @@ -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 Songs; diff --git a/src/sc_man.cpp b/src/sc_man.cpp index 2a515d91bd..277604d686 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -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; } //========================================================================== diff --git a/src/sc_man.h b/src/sc_man.h index 44dd9370a5..9962cbde09 100644 --- a/src/sc_man.h +++ b/src/sc_man.h @@ -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); diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index a0af21c14a..cb927bb502 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -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; } } diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 19db0161db..28f839c6c8 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -803,18 +803,17 @@ CCMD (writemidi) } TArray midi; - FILE *f; bool success; static_cast(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) { diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 7bc5a31e5d..4c796ead59 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -239,7 +239,7 @@ public: void Stop(); protected: - FILE *File; + FileWriter *File; }; // WildMidi implementation of a MIDI device --------------------------------- diff --git a/src/sound/mididevices/music_opldumper_mididevice.cpp b/src/sound/mididevices/music_opldumper_mididevice.cpp index e301a30548..3519103e85 100644 --- a/src/sound/mididevices/music_opldumper_mididevice.cpp +++ b/src/sound/mididevices/music_opldumper_mididevice.cpp @@ -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()); diff --git a/src/sound/mididevices/music_timidity_mididevice.cpp b/src/sound/mididevices/music_timidity_mididevice.cpp index cacddf5426..474c0efa9b 100644 --- a/src/sound/mididevices/music_timidity_mididevice.cpp +++ b/src/sound/mididevices/music_timidity_mididevice.cpp @@ -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; diff --git a/src/sound/mididevices/music_timiditypp_mididevice.cpp b/src/sound/mididevices/music_timiditypp_mididevice.cpp index d4c03534d4..42733ce385 100644 --- a/src/sound/mididevices/music_timiditypp_mididevice.cpp +++ b/src/sound/mididevices/music_timiditypp_mididevice.cpp @@ -43,6 +43,7 @@ #include "templates.h" #include "version.h" #include "tmpfileplus.h" +#include "m_misc.h" #ifndef _WIN32 #include @@ -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; diff --git a/src/statistics.cpp b/src/statistics.cpp index 2abd0bf12c..865ba04110 100644 --- a/src/statistics.cpp +++ b/src/statistics.cpp @@ -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 &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 &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) 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;jinfo[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 &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;kPrintf("\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; } diff --git a/src/swrenderer/drawers/r_draw.cpp b/src/swrenderer/drawers/r_draw.cpp index bc7eb731dc..3250c11860 100644 --- a/src/swrenderer/drawers/r_draw.cpp +++ b/src/swrenderer/drawers/r_draw.cpp @@ -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(args, idepth); + } + + void SWPixelFormatDrawers::DrawDepthWallColumn(const WallDrawerArgs &args, float idepth) + { + Queue->Push(args, idepth); + } + + void SWPixelFormatDrawers::DrawDepthSpan(const SpanDrawerArgs &args, float idepth) + { + Queue->Push(args, idepth); + } } diff --git a/src/swrenderer/drawers/r_draw.h b/src/swrenderer/drawers/r_draw.h index 4672a4fd31..fa83ca6f61 100644 --- a/src/swrenderer/drawers/r_draw.h +++ b/src/swrenderer/drawers/r_draw.h @@ -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; }; diff --git a/src/swrenderer/line/r_walldraw.cpp b/src/swrenderer/line/r_walldraw.cpp index 5a8a4f465c..5b7518440a 100644 --- a/src/swrenderer/line/r_walldraw.cpp +++ b/src/swrenderer/line/r_walldraw.cpp @@ -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; diff --git a/src/swrenderer/plane/r_flatplane.cpp b/src/swrenderer/plane/r_flatplane.cpp index 513ce9ccc3..82e27f89f2 100644 --- a/src/swrenderer/plane/r_flatplane.cpp +++ b/src/swrenderer/plane/r_flatplane.cpp @@ -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); } ///////////////////////////////////////////////////////////////////////// diff --git a/src/swrenderer/plane/r_skyplane.cpp b/src/swrenderer/plane/r_skyplane.cpp index d79c06909e..ef7a6b898b 100644 --- a/src/swrenderer/plane/r_skyplane.cpp +++ b/src/swrenderer/plane/r_skyplane.cpp @@ -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) diff --git a/src/swrenderer/plane/r_slopeplane.cpp b/src/swrenderer/plane/r_slopeplane.cpp index b4fcb51854..bf9c84666e 100644 --- a/src/swrenderer/plane/r_slopeplane.cpp +++ b/src/swrenderer/plane/r_slopeplane.cpp @@ -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); } } diff --git a/src/swrenderer/r_all.cpp b/src/swrenderer/r_all.cpp index 296fc04cf9..91586be6fe 100644 --- a/src/swrenderer/r_all.cpp +++ b/src/swrenderer/r_all.cpp @@ -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" diff --git a/src/swrenderer/r_renderthread.h b/src/swrenderer/r_renderthread.h index 6bc23bba5f..3e559155bf 100644 --- a/src/swrenderer/r_renderthread.h +++ b/src/swrenderer/r_renderthread.h @@ -29,6 +29,8 @@ class DrawerCommandQueue; typedef std::shared_ptr DrawerCommandQueuePtr; class RenderMemory; +EXTERN_CVAR(Bool, r_models); + namespace swrenderer { class VisibleSpriteList; diff --git a/src/swrenderer/scene/r_opaque_pass.cpp b/src/swrenderer/scene/r_opaque_pass.cpp index 03467ce729..f18cdc2ec3 100644 --- a/src/swrenderer/scene/r_opaque_pass.cpp +++ b/src/swrenderer/scene/r_opaque_pass.cpp @@ -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); + } + } } } } diff --git a/src/swrenderer/scene/r_scene.cpp b/src/swrenderer/scene/r_scene.cpp index 4667f25ebf..8c0b81cefc 100644 --- a/src/swrenderer/scene/r_scene.cpp +++ b/src/swrenderer/scene/r_scene.cpp @@ -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) diff --git a/src/swrenderer/things/r_model.cpp b/src/swrenderer/things/r_model.cpp new file mode 100644 index 0000000000..f86a7e3849 --- /dev/null +++ b/src/swrenderer/things/r_model.cpp @@ -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 +#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(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(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(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(); + *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(); + *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(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(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]; + } + } +} diff --git a/src/swrenderer/things/r_model.h b/src/swrenderer/things/r_model.h new file mode 100644 index 0000000000..94ca1d9097 --- /dev/null +++ b/src/swrenderer/things/r_model.h @@ -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 mVertexBuffer; + TArray mIndexBuffer; + }; +} diff --git a/src/swrenderer/things/r_playersprite.cpp b/src/swrenderer/things/r_playersprite.cpp index 2a51310b6b..41ec47239f 100644 --- a/src/swrenderer/things/r_playersprite.cpp +++ b/src/swrenderer/things/r_playersprite.cpp @@ -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; diff --git a/src/swrenderer/things/r_playersprite.h b/src/swrenderer/things/r_playersprite.h index 755997a2a4..3dbfd6edb4 100644 --- a/src/swrenderer/things/r_playersprite.h +++ b/src/swrenderer/things/r_playersprite.h @@ -97,5 +97,6 @@ namespace swrenderer TArray AcceleratedSprites; sector_t tempsec; + bool renderHUDModel = false; }; } diff --git a/src/swrenderer/things/r_visiblesprite.cpp b/src/swrenderer/things/r_visiblesprite.cpp index e9ddec275b..2a1d36eebe 100644 --- a/src/swrenderer/things/r_visiblesprite.cpp +++ b/src/swrenderer/things/r_visiblesprite.cpp @@ -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; diff --git a/src/swrenderer/things/r_visiblesprite.h b/src/swrenderer/things/r_visiblesprite.h index f31d08b585..c9fff33270 100644 --- a/src/swrenderer/things/r_visiblesprite.h +++ b/src/swrenderer/things/r_visiblesprite.h @@ -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; diff --git a/src/swrenderer/viewport/r_skydrawer.cpp b/src/swrenderer/viewport/r_skydrawer.cpp index 47409bf086..16e2d2ab38 100644 --- a/src/swrenderer/viewport/r_skydrawer.cpp +++ b/src/swrenderer/viewport/r_skydrawer.cpp @@ -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); diff --git a/src/swrenderer/viewport/r_skydrawer.h b/src/swrenderer/viewport/r_skydrawer.h index 4d7d448396..24c7e6f080 100644 --- a/src/swrenderer/viewport/r_skydrawer.h +++ b/src/swrenderer/viewport/r_skydrawer.h @@ -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); diff --git a/src/swrenderer/viewport/r_spandrawer.cpp b/src/swrenderer/viewport/r_spandrawer.cpp index 245cac2abf..ffc4dfc5ff 100644 --- a/src/swrenderer/viewport/r_spandrawer.cpp +++ b/src/swrenderer/viewport/r_spandrawer.cpp @@ -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); diff --git a/src/swrenderer/viewport/r_spandrawer.h b/src/swrenderer/viewport/r_spandrawer.h index 2dd9a959aa..fe3363c989 100644 --- a/src/swrenderer/viewport/r_spandrawer.h +++ b/src/swrenderer/viewport/r_spandrawer.h @@ -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); diff --git a/src/swrenderer/viewport/r_viewport.cpp b/src/swrenderer/viewport/r_viewport.cpp index b243f22655..a0535e4340 100644 --- a/src/swrenderer/viewport/r_viewport.cpp +++ b/src/swrenderer/viewport/r_viewport.cpp @@ -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; diff --git a/src/swrenderer/viewport/r_viewport.h b/src/swrenderer/viewport/r_viewport.h index 1263425ac2..b8ce166a7e 100644 --- a/src/swrenderer/viewport/r_viewport.h +++ b/src/swrenderer/viewport/r_viewport.h @@ -5,6 +5,7 @@ #include #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; diff --git a/src/swrenderer/viewport/r_walldrawer.cpp b/src/swrenderer/viewport/r_walldrawer.cpp index c61ed33032..50530eec52 100644 --- a/src/swrenderer/viewport/r_walldrawer.cpp +++ b/src/swrenderer/viewport/r_walldrawer.cpp @@ -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); diff --git a/src/swrenderer/viewport/r_walldrawer.h b/src/swrenderer/viewport/r_walldrawer.h index 5dde5cc5c7..54bec778d1 100644 --- a/src/swrenderer/viewport/r_walldrawer.h +++ b/src/swrenderer/viewport/r_walldrawer.h @@ -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; } diff --git a/src/textures/buildtexture.cpp b/src/textures/buildtexture.cpp index cb7786200c..d23e5e6f2f 100644 --- a/src/textures/buildtexture.cpp +++ b/src/textures/buildtexture.cpp @@ -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); } } diff --git a/src/tmpfileplus.c b/src/tmpfileplus.cpp similarity index 55% rename from src/tmpfileplus.c rename to src/tmpfileplus.cpp index ddb71de092..bfe021dbb3 100644 --- a/src/tmpfileplus.c +++ b/src/tmpfileplus.cpp @@ -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 @@ -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; -} - - diff --git a/src/tmpfileplus.h b/src/tmpfileplus.h index e32ff5042d..06219edd6f 100644 --- a/src/tmpfileplus.h +++ b/src/tmpfileplus.h @@ -23,9 +23,7 @@ #include -#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_ */ diff --git a/src/v_font.cpp b/src/v_font.cpp index b475fb5581..9716f27444 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -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; } } diff --git a/src/v_text.cpp b/src/v_text.cpp index cf8ce8cc7b..f4829ec183 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -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) { diff --git a/src/v_text.h b/src/v_text.h index b76024fa51..cd7d3e6ad4 100644 --- a/src/v_text.h +++ b/src/v_text.h @@ -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__ diff --git a/src/v_video.cpp b/src/v_video.cpp index 01ae8b428e..814dc46150 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -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], diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 412450d0a8..1e1de76f0b 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -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; diff --git a/src/win32/i_specialpaths.cpp b/src/win32/i_specialpaths.cpp index 58c87a8ca8..4a790798f1 100644 --- a/src/win32/i_specialpaths.cpp +++ b/src/win32/i_specialpaths.cpp @@ -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; } diff --git a/src/win32/win32swiface.h b/src/win32/win32swiface.h index 59101c6023..657b120a32 100644 --- a/src/win32/win32swiface.h +++ b/src/win32/win32swiface.h @@ -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); }