- added a FileWriter class (taken from another project of mine) and changed m_png.cpp to use it.

This is so that PNGs can be written to memory, not just to an external file. stdio's FILE cannot be easily redirected but a C++ class can.
The writer is very simple and primitive right now, allowing no seeking, but for the job at hand it is sufficient.

Note that large parts of savegame creation have been disabled, because they are about to be rewritten and it makes no sense to adjust them all before.
This commit is contained in:
Christoph Oelckers 2016-09-21 09:01:12 +02:00
parent 075e98c967
commit 67239cd623
9 changed files with 165 additions and 52 deletions

View file

@ -600,3 +600,58 @@ char *MemoryArrayReader::Gets(char *strbuf, int len)
{
return GetsFromBuffer((char*)&buf[0], strbuf, len);
}
//==========================================================================
//
// FileWriter (the motivation here is to have a buffer writing subclass)
//
//==========================================================================
bool FileWriter::OpenDirect(const char *filename)
{
File = fopen(filename, "wb");
return (File != NULL);
}
FileWriter *FileWriter::Open(const char *filename)
{
FileWriter *fwrit = new FileWriter();
if (fwrit->OpenDirect(filename))
{
return fwrit;
}
delete fwrit;
return NULL;
}
size_t FileWriter::Write(const void *buffer, size_t len)
{
if (File != NULL)
{
return fwrite(buffer, 1, len, File);
}
else
{
return 0;
}
}
size_t FileWriter::Printf(const char *fmt, ...)
{
va_list ap;
FString out;
va_start(ap, fmt);
out.VFormat(fmt, ap);
va_end(ap);
return Write(out.GetChars(), out.Len());
}
size_t BufferWriter::Write(const void *buffer, size_t len)
{
unsigned int ofs = mBuffer.Reserve((unsigned)len);
memcpy(&mBuffer[ofs], buffer, len);
return len;
}

View file

@ -356,4 +356,46 @@ protected:
};
class FileWriter
{
protected:
bool OpenDirect(const char *filename);
FileWriter()
{
File = NULL;
}
public:
virtual ~FileWriter()
{
if (File != NULL) fclose(File);
}
static FileWriter *Open(const char *filename);
virtual size_t Write(const void *buffer, size_t len);
size_t Printf(const char *fmt, ...);
protected:
FILE *File;
protected:
bool CloseOnDestruct;
};
class BufferWriter : public FileWriter
{
protected:
TArray<unsigned char> mBuffer;
public:
BufferWriter() {}
virtual size_t Write(const void *buffer, size_t len) override;
TArray<unsigned char> *GetBuffer() { return &mBuffer; }
};
#endif

View file

@ -1828,6 +1828,7 @@ bool G_CheckSaveGameWads (PNGHandle *png, bool printwarn)
void G_DoLoadGame ()
{
#if 0 // SAVEGAME
char sigcheck[20];
char *text = NULL;
char *map;
@ -1981,6 +1982,7 @@ void G_DoLoadGame ()
// amount of memory in use, so bring it down now by starting a
// collection.
GC::StartCollection();
#endif
}
@ -2102,6 +2104,7 @@ void G_DoAutoSave ()
static void PutSaveWads (FILE *file)
{
#if 0 // SAVEGAME
const char *name;
// Name of IWAD
@ -2114,10 +2117,12 @@ static void PutSaveWads (FILE *file)
name = Wads.GetWadName (Wads.GetLumpFile (level.lumpnum));
M_AppendPNGText (file, "Map WAD", name);
}
#endif
}
static void PutSaveComment (FILE *file)
{
#if 0 // SAVEGAME
char comment[256];
const char *readableTime;
WORD len;
@ -2147,9 +2152,10 @@ static void PutSaveComment (FILE *file)
// Write out the comment
M_AppendPNGText (file, "Comment", comment);
#endif
}
static void PutSavePic (FILE *file, int width, int height)
static void PutSavePic (FileWriter *file, int width, int height)
{
if (width <= 0 || height <= 0 || !storesavepic)
{
@ -2194,6 +2200,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
}
SaveVersion = SAVEVER;
#if 0 // SAVEGAME
PutSavePic (stdfile, SAVEPICWIDTH, SAVEPICHEIGHT);
mysnprintf(buf, countof(buf), GAMENAME " %s", GetVersionString());
M_AppendPNGText (stdfile, "Software", buf);
@ -2249,7 +2256,9 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
}
fclose(stdfile);
}
if (success)
#endif
bool success = true;
if (success)
{
if (longsavemessages) Printf ("%s (%s)\n", GStrings("GGSAVED"), filename.GetChars());
else Printf ("%s\n", GStrings("GGSAVED"));

View file

@ -449,10 +449,15 @@ struct pcx_t
};
inline void putc(char chr, FileWriter *file)
{
file->Write(&chr, 1);
}
//
// WritePCXfile
//
void WritePCXfile (FILE *file, const BYTE *buffer, const PalEntry *palette,
void WritePCXfile (FileWriter *file, const BYTE *buffer, const PalEntry *palette,
ESSType color_type, int width, int height, int pitch)
{
BYTE temprow[MAXWIDTH * 3];
@ -480,7 +485,7 @@ void WritePCXfile (FILE *file, const BYTE *buffer, const PalEntry *palette,
pcx.palette_type = 1; // not a grey scale
memset (pcx.filler, 0, sizeof(pcx.filler));
fwrite (&pcx, 128, 1, file);
file->Write(&pcx, 128);
bytes_per_row_minus_one = ((color_type == SS_PAL) ? width : width * 3) - 1;
@ -593,7 +598,7 @@ void WritePCXfile (FILE *file, const BYTE *buffer, const PalEntry *palette,
//
// WritePNGfile
//
void WritePNGfile (FILE *file, const BYTE *buffer, const PalEntry *palette,
void WritePNGfile (FileWriter *file, const BYTE *buffer, const PalEntry *palette,
ESSType color_type, int width, int height, int pitch)
{
char software[100];
@ -655,7 +660,7 @@ static bool FindFreeName (FString &fullname, const char *extension)
void M_ScreenShot (const char *filename)
{
FILE *file;
FileWriter *file;
FString autoname;
bool writepcx = (stricmp (screenshot_type, "pcx") == 0); // PNG is the default
@ -709,7 +714,7 @@ void M_ScreenShot (const char *filename)
{
screen->GetFlashedPalette(palette);
}
file = fopen (autoname, "wb");
file = FileWriter::Open(autoname);
if (file == NULL)
{
Printf ("Could not open %s\n", autoname.GetChars());
@ -726,7 +731,7 @@ void M_ScreenShot (const char *filename)
WritePNGfile(file, buffer, palette, color_type,
screen->GetWidth(), screen->GetHeight(), pitch);
}
fclose(file);
delete file;
screen->ReleaseScreenshotBuffer();
if (!screenshot_quiet)

View file

@ -101,7 +101,7 @@ PNGHandle::~PNGHandle ()
static inline void MakeChunk (void *where, DWORD type, size_t len);
static inline void StuffPalette (const PalEntry *from, BYTE *to);
static bool WriteIDAT (FILE *file, const BYTE *data, int len);
static bool WriteIDAT (FileWriter *file, const BYTE *data, int len);
static void UnfilterRow (int width, BYTE *dest, BYTE *stream, BYTE *prev, int bpp);
static void UnpackPixels (int width, int bytesPerRow, int bitdepth, const BYTE *rowin, BYTE *rowout, bool grayscale);
@ -131,7 +131,7 @@ CVAR(Float, png_gamma, 0.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
//
//==========================================================================
bool M_CreatePNG (FILE *file, const BYTE *buffer, const PalEntry *palette,
bool M_CreatePNG (FileWriter *file, const BYTE *buffer, const PalEntry *palette,
ESSType color_type, int width, int height, int pitch)
{
BYTE work[8 + // signature
@ -171,7 +171,7 @@ bool M_CreatePNG (FILE *file, const BYTE *buffer, const PalEntry *palette,
work_len = sizeof(work) - (12+256*3);
}
if (fwrite (work, 1, work_len, file) != work_len)
if (file->Write (work, work_len) != work_len)
return false;
return M_SaveBitmap (buffer, color_type, width, height, pitch, file);
@ -185,7 +185,7 @@ bool M_CreatePNG (FILE *file, const BYTE *buffer, const PalEntry *palette,
//
//==========================================================================
bool M_CreateDummyPNG (FILE *file)
bool M_CreateDummyPNG (FileWriter *file)
{
static const BYTE dummyPNG[] =
{
@ -195,7 +195,7 @@ bool M_CreateDummyPNG (FILE *file)
0,0,0,10,'I','D','A','T',
104,222,99,96,0,0,0,2,0,1,0x9f,0x65,0x0e,0x18
};
return fwrite (dummyPNG, 1, sizeof(dummyPNG), file) == sizeof(dummyPNG);
return file->Write (dummyPNG, sizeof(dummyPNG)) == sizeof(dummyPNG);
}
@ -207,10 +207,10 @@ bool M_CreateDummyPNG (FILE *file)
//
//==========================================================================
bool M_FinishPNG (FILE *file)
bool M_FinishPNG (FileWriter *file)
{
static const BYTE iend[12] = { 0,0,0,0,73,69,78,68,174,66,96,130 };
return fwrite (iend, 1, 12, file) == 12;
return file->Write (iend, 12) == 12;
}
//==========================================================================
@ -221,13 +221,13 @@ bool M_FinishPNG (FILE *file)
//
//==========================================================================
bool M_AppendPNGChunk (FILE *file, DWORD chunkID, const BYTE *chunkData, DWORD len)
bool M_AppendPNGChunk (FileWriter *file, DWORD chunkID, const BYTE *chunkData, DWORD len)
{
DWORD head[2] = { BigLong((unsigned int)len), chunkID };
DWORD crc;
if (fwrite (head, 1, 8, file) == 8 &&
(len == 0 || fwrite (chunkData, 1, len, file) == len))
if (file->Write (head, 8) == 8 &&
(len == 0 || file->Write (chunkData, len) == len))
{
crc = CalcCRC32 ((BYTE *)&head[1], 4);
if (len != 0)
@ -235,7 +235,7 @@ bool M_AppendPNGChunk (FILE *file, DWORD chunkID, const BYTE *chunkData, DWORD l
crc = AddCRC32 (crc, chunkData, len);
}
crc = BigLong((unsigned int)crc);
return fwrite (&crc, 1, 4, file) == 4;
return file->Write (&crc, 4) == 4;
}
return false;
}
@ -248,7 +248,7 @@ bool M_AppendPNGChunk (FILE *file, DWORD chunkID, const BYTE *chunkData, DWORD l
//
//==========================================================================
bool M_AppendPNGText (FILE *file, const char *keyword, const char *text)
bool M_AppendPNGText (FileWriter *file, const char *keyword, const char *text)
{
struct { DWORD len, id; char key[80]; } head;
int len = (int)strlen (text);
@ -261,8 +261,8 @@ bool M_AppendPNGText (FILE *file, const char *keyword, const char *text)
strncpy (head.key, keyword, keylen);
head.key[keylen] = 0;
if ((int)fwrite (&head, 1, keylen + 9, file) == keylen + 9 &&
(int)fwrite (text, 1, len, file) == len)
if ((int)file->Write (&head, keylen + 9) == keylen + 9 &&
(int)file->Write (text, len) == len)
{
crc = CalcCRC32 ((BYTE *)&head+4, keylen + 5);
if (len != 0)
@ -270,7 +270,7 @@ bool M_AppendPNGText (FILE *file, const char *keyword, const char *text)
crc = AddCRC32 (crc, (BYTE *)text, len);
}
crc = BigLong((unsigned int)crc);
return fwrite (&crc, 1, 4, file) == 4;
return file->Write (&crc, 4) == 4;
}
return false;
}
@ -900,7 +900,7 @@ static int SelectFilter(Byte row[5][1 + MAXWIDTH*3], Byte prior[MAXWIDTH*3], int
//
//==========================================================================
bool M_SaveBitmap(const BYTE *from, ESSType color_type, int width, int height, int pitch, FILE *file)
bool M_SaveBitmap(const BYTE *from, ESSType color_type, int width, int height, int pitch, FileWriter *file)
{
#if USE_FILTER_HEURISTIC
Byte prior[MAXWIDTH*3];
@ -1040,7 +1040,7 @@ bool M_SaveBitmap(const BYTE *from, ESSType color_type, int width, int height, i
//
//==========================================================================
static bool WriteIDAT (FILE *file, const BYTE *data, int len)
static bool WriteIDAT (FileWriter *file, const BYTE *data, int len)
{
DWORD foo[2], crc;
@ -1049,9 +1049,9 @@ static bool WriteIDAT (FILE *file, const BYTE *data, int len)
crc = CalcCRC32 ((BYTE *)&foo[1], 4);
crc = BigLong ((unsigned int)AddCRC32 (crc, data, len));
if (fwrite (foo, 1, 8, file) != 8 ||
fwrite (data, 1, len, file) != (size_t)len ||
fwrite (&crc, 1, 4, file) != 4)
if (file->Write (foo, 8) != 8 ||
file->Write (data, len) != (size_t)len ||
file->Write (&crc, 4) != 4)
{
return false;
}

View file

@ -36,6 +36,7 @@
#include <stdio.h>
#include "doomtype.h"
#include "v_video.h"
#include "files.h"
// PNG Writing --------------------------------------------------------------
@ -43,22 +44,22 @@
// The passed file should be a newly created file.
// This function writes the PNG signature and the IHDR, gAMA, PLTE, and IDAT
// chunks.
bool M_CreatePNG (FILE *file, const BYTE *buffer, const PalEntry *pal,
bool M_CreatePNG (FileWriter *file, const BYTE *buffer, const PalEntry *pal,
ESSType color_type, int width, int height, int pitch);
// Creates a grayscale 1x1 PNG file. Used for savegames without savepics.
bool M_CreateDummyPNG (FILE *file);
bool M_CreateDummyPNG (FileWriter *file);
// Appends any chunk to a PNG file started with M_CreatePNG.
bool M_AppendPNGChunk (FILE *file, DWORD chunkID, const BYTE *chunkData, DWORD len);
bool M_AppendPNGChunk (FileWriter *file, DWORD chunkID, const BYTE *chunkData, DWORD len);
// Adds a tEXt chunk to a PNG file started with M_CreatePNG.
bool M_AppendPNGText (FILE *file, const char *keyword, const char *text);
bool M_AppendPNGText (FileWriter *file, const char *keyword, const char *text);
// Appends the IEND chunk to a PNG file.
bool M_FinishPNG (FILE *file);
bool M_FinishPNG (FileWriter *file);
bool M_SaveBitmap(const BYTE *from, ESSType color_type, int width, int height, int pitch, FILE *file);
bool M_SaveBitmap(const BYTE *from, ESSType color_type, int width, int height, int pitch, FileWriter *file);
// PNG Reading --------------------------------------------------------------

View file

@ -11,6 +11,7 @@ class AActor;
class player_t;
struct sector_t;
class FCanvasTexture;
class FileWriter;
struct FRenderer
{
@ -37,7 +38,7 @@ struct FRenderer
virtual void RemapVoxels() {}
// renders view to a savegame picture
virtual void WriteSavePic (player_t *player, FILE *file, int width, int height) = 0;
virtual void WriteSavePic (player_t *player, FileWriter *file, int width, int height) = 0;
// draws player sprites with hardware acceleration (only useful for software rendering)
virtual void DrawRemainingPlayerSprites() {}

View file

@ -179,7 +179,7 @@ void FSoftwareRenderer::RemapVoxels()
//
//===========================================================================
void FSoftwareRenderer::WriteSavePic (player_t *player, FILE *file, int width, int height)
void FSoftwareRenderer::WriteSavePic (player_t *player, FileWriter *file, int width, int height)
{
DCanvas *pic = new DSimpleCanvas (width, height);
PalEntry palette[256];

View file

@ -6,35 +6,35 @@
struct FSoftwareRenderer : public FRenderer
{
// Can be overridden so that the colormaps for sector color/fade won't be built.
virtual bool UsesColormap() const;
virtual bool UsesColormap() const override;
// precache one texture
void PrecacheTexture(FTexture *tex, int cache);
virtual void Precache(BYTE *texhitlist, TMap<PClassActor*, bool> &actorhitlist);
virtual void Precache(BYTE *texhitlist, TMap<PClassActor*, bool> &actorhitlist) override;
// render 3D view
virtual void RenderView(player_t *player);
virtual void RenderView(player_t *player) override;
// Remap voxel palette
virtual void RemapVoxels();
virtual void RemapVoxels() override;
// renders view to a savegame picture
virtual void WriteSavePic (player_t *player, FILE *file, int width, int height);
virtual void WriteSavePic (player_t *player, FileWriter *file, int width, int height) override;
// draws player sprites with hardware acceleration (only useful for software rendering)
virtual void DrawRemainingPlayerSprites();
virtual void DrawRemainingPlayerSprites() override;
virtual int GetMaxViewPitch(bool down);
virtual int GetMaxViewPitch(bool down) override;
void OnModeSet ();
void ErrorCleanup ();
void ClearBuffer(int color);
void Init();
void SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio);
void SetupFrame(player_t *player);
void CopyStackedViewParameters();
void RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, int fov);
sector_t *FakeFlat(sector_t *sec, sector_t *tempsec, int *floorlightlevel, int *ceilinglightlevel, bool back);
void OnModeSet () override;
void ErrorCleanup () override;
void ClearBuffer(int color) override;
void Init() override;
void SetWindow (int windowSize, int fullWidth, int fullHeight, int stHeight, float trueratio) override;
void SetupFrame(player_t *player) override;
void CopyStackedViewParameters() override;
void RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, int fov) override;
sector_t *FakeFlat(sector_t *sec, sector_t *tempsec, int *floorlightlevel, int *ceilinglightlevel, bool back) override;
};