mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 23:02:08 +00:00
- Added support for 24-bit screenshots, so now accelerated 2D screenshots
can work. - Tweaked the box splitting algorithm for packed textures to hopefully produce less wasted space. SVN r696 (trunk)
This commit is contained in:
parent
88549aebcd
commit
9902d73a24
10 changed files with 862 additions and 230 deletions
|
@ -1,11 +1,15 @@
|
|||
January 11, 2008
|
||||
- Added support for 24-bit screenshots, so now accelerated 2D screenshots
|
||||
can work.
|
||||
- Tweaked the box splitting algorithm for packed textures to hopefully
|
||||
produce less wasted space.
|
||||
- For compatibility with the software renderer, D3DFB::DrawTextureV needs to
|
||||
truncate the coordinates to integers before sending them to the hardware.
|
||||
Otherwise, there can be one pixel gaps compared to the software renderer,
|
||||
because the hardware is rounding to nearest but the software renderer is
|
||||
simply truncating the fractional part of the coordinate. This is the real
|
||||
cause of the gap at the top of the status bar at 1152x864 (and another gap
|
||||
to the left of the status bar at 800x500).
|
||||
cause of the gap above the status bar at 1152x864 (and another gap to the
|
||||
left of the status bar at 800x500).
|
||||
- Fixed: When D3DFB::DrawTextureV had to clip a tile, it adjusted the
|
||||
texture coordinates erroneously, still using the old calculations from
|
||||
before texture packing was implemented.
|
||||
|
|
|
@ -1977,7 +1977,7 @@ static void PutSavePic (FILE *file, int width, int height)
|
|||
P_CheckPlayerSprites();
|
||||
R_RenderViewToCanvas (players[consoleplayer].mo, pic, 0, 0, width, height);
|
||||
screen->GetFlashedPalette (palette);
|
||||
M_CreatePNG (file, pic, palette);
|
||||
M_CreatePNG (file, pic->GetBuffer(), palette, SS_PAL, width, height, pic->GetPitch());
|
||||
pic->Unlock ();
|
||||
delete pic;
|
||||
}
|
||||
|
|
145
src/m_misc.cpp
145
src/m_misc.cpp
|
@ -432,24 +432,21 @@ typedef struct
|
|||
//
|
||||
// WritePCXfile
|
||||
//
|
||||
void WritePCXfile (FILE *file, const DCanvas *canvas, const PalEntry *palette)
|
||||
void WritePCXfile (FILE *file, const BYTE *buffer, const PalEntry *palette,
|
||||
ESSType color_type, int width, int height, int pitch)
|
||||
{
|
||||
BYTE temprow[MAXWIDTH * 3];
|
||||
const BYTE *data;
|
||||
int x, y;
|
||||
int runlen;
|
||||
int bytes_per_row_minus_one;
|
||||
BYTE color;
|
||||
pcx_t pcx;
|
||||
BYTE *data;
|
||||
int width, height, pitch;
|
||||
|
||||
data = canvas->GetBuffer ();
|
||||
width = canvas->GetWidth ();
|
||||
height = canvas->GetHeight ();
|
||||
pitch = canvas->GetPitch ();
|
||||
|
||||
pcx.manufacturer = 10; // PCX id
|
||||
pcx.version = 5; // 256 color
|
||||
pcx.version = 5; // 256 (or more) colors
|
||||
pcx.encoding = 1;
|
||||
pcx.bits_per_pixel = 8; // 256 color
|
||||
pcx.bits_per_pixel = 8; // 256 (or more) colors
|
||||
pcx.xmin = 0;
|
||||
pcx.ymin = 0;
|
||||
pcx.xmax = LittleShort(width-1);
|
||||
|
@ -458,20 +455,52 @@ void WritePCXfile (FILE *file, const DCanvas *canvas, const PalEntry *palette)
|
|||
pcx.vdpi = LittleShort(75);
|
||||
memset (pcx.palette, 0, sizeof(pcx.palette));
|
||||
pcx.reserved = 0;
|
||||
pcx.color_planes = 1; // chunky image
|
||||
pcx.color_planes = (color_type == SS_PAL) ? 1 : 3; // chunky image
|
||||
pcx.bytes_per_line = width + (width & 1);
|
||||
pcx.palette_type = 1; // not a grey scale
|
||||
memset (pcx.filler, 0, sizeof(pcx.filler));
|
||||
|
||||
fwrite (&pcx, 128, 1, file);
|
||||
|
||||
bytes_per_row_minus_one = ((color_type == SS_PAL) ? width : width * 3) - 1;
|
||||
|
||||
// pack the image
|
||||
for (y = height; y > 0; y--)
|
||||
{
|
||||
switch (color_type)
|
||||
{
|
||||
case SS_PAL:
|
||||
data = buffer;
|
||||
break;
|
||||
|
||||
case SS_RGB:
|
||||
// Unpack RGB into separate planes.
|
||||
for (int i = 0; i < width; ++i)
|
||||
{
|
||||
temprow[i ] = buffer[i*3];
|
||||
temprow[i + width ] = buffer[i*3 + 1];
|
||||
temprow[i + width * 2] = buffer[i*3 + 2];
|
||||
}
|
||||
data = temprow;
|
||||
break;
|
||||
|
||||
case SS_BGRA:
|
||||
// Unpack RGB into separate planes, discarding A.
|
||||
for (int i = 0; i < width; ++i)
|
||||
{
|
||||
temprow[i ] = buffer[i*4 + 2];
|
||||
temprow[i + width ] = buffer[i*4 + 1];
|
||||
temprow[i + width * 2] = buffer[i*4];
|
||||
}
|
||||
data = temprow;
|
||||
break;
|
||||
}
|
||||
buffer += pitch;
|
||||
|
||||
color = *data++;
|
||||
runlen = 1;
|
||||
|
||||
for (x = width - 1; x > 0; x--)
|
||||
for (x = bytes_per_row_minus_one; x > 0; x--)
|
||||
{
|
||||
if (*data == color)
|
||||
{
|
||||
|
@ -522,26 +551,28 @@ void WritePCXfile (FILE *file, const DCanvas *canvas, const PalEntry *palette)
|
|||
|
||||
if (width & 1)
|
||||
putc (0, file);
|
||||
|
||||
data += pitch - width;
|
||||
}
|
||||
|
||||
// write the palette
|
||||
putc (12, file); // palette ID byte
|
||||
for (x = 0; x < 256; x++, palette++)
|
||||
if (color_type == SS_PAL)
|
||||
{
|
||||
putc (palette->r, file);
|
||||
putc (palette->g, file);
|
||||
putc (palette->b, file);
|
||||
putc (12, file); // palette ID byte
|
||||
for (x = 0; x < 256; x++, palette++)
|
||||
{
|
||||
putc (palette->r, file);
|
||||
putc (palette->g, file);
|
||||
putc (palette->b, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// WritePNGfile
|
||||
//
|
||||
void WritePNGfile (FILE *file, const DCanvas *canvas, const PalEntry *palette)
|
||||
void WritePNGfile (FILE *file, const BYTE *buffer, const PalEntry *palette,
|
||||
ESSType color_type, int width, int height, int pitch)
|
||||
{
|
||||
if (!M_CreatePNG (file, canvas, palette) ||
|
||||
if (!M_CreatePNG (file, buffer, palette, color_type, width, height, pitch) ||
|
||||
!M_AppendPNGText (file, "Software", GAMENAME DOTVERSIONSTR) ||
|
||||
!M_FinishPNG (file))
|
||||
{
|
||||
|
@ -572,8 +603,9 @@ static bool FindFreeName (FString &fullname, const char *extension)
|
|||
|
||||
void M_ScreenShot (const char *filename)
|
||||
{
|
||||
FILE *file;
|
||||
FString autoname;
|
||||
bool writepcx = screen->CanWritePCX() && (stricmp (screenshot_type, "pcx") == 0); // PNG is the default
|
||||
bool writepcx = (stricmp (screenshot_type, "pcx") == 0); // PNG is the default
|
||||
|
||||
// find a file name to save it to
|
||||
if (filename == NULL || filename[0] == '\0')
|
||||
|
@ -614,46 +646,51 @@ void M_ScreenShot (const char *filename)
|
|||
CreatePath(screenshot_dir);
|
||||
|
||||
// save the screenshot
|
||||
screen->Save(autoname, writepcx);
|
||||
const BYTE *buffer;
|
||||
int pitch;
|
||||
ESSType color_type;
|
||||
|
||||
if (!screenshot_quiet)
|
||||
screen->GetScreenshotBuffer(buffer, pitch, color_type);
|
||||
if (buffer != NULL)
|
||||
{
|
||||
Printf ("Captured %s\n", autoname.GetChars());
|
||||
}
|
||||
}
|
||||
PalEntry palette[256];
|
||||
|
||||
bool DCanvas::CanWritePCX()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (color_type == SS_PAL)
|
||||
{
|
||||
screen->GetFlashedPalette(palette);
|
||||
}
|
||||
file = fopen (autoname, "wb");
|
||||
if (file == NULL)
|
||||
{
|
||||
Printf ("Could not open %s\n", autoname.GetChars());
|
||||
screen->ReleaseScreenshotBuffer();
|
||||
return;
|
||||
}
|
||||
if (writepcx)
|
||||
{
|
||||
WritePCXfile(file, buffer, palette, color_type,
|
||||
screen->GetWidth(), screen->GetHeight(), pitch);
|
||||
}
|
||||
else
|
||||
{
|
||||
WritePNGfile(file, buffer, palette, color_type,
|
||||
screen->GetWidth(), screen->GetHeight(), pitch);
|
||||
}
|
||||
fclose(file);
|
||||
screen->ReleaseScreenshotBuffer();
|
||||
|
||||
void DCanvas::Save(const char *filename, bool writepcx)
|
||||
{
|
||||
FILE *file;
|
||||
|
||||
Lock (true);
|
||||
|
||||
PalEntry palette[256];
|
||||
screen->GetFlashedPalette (palette);
|
||||
|
||||
file = fopen (filename, "wb");
|
||||
if (file == NULL)
|
||||
{
|
||||
Printf ("Could not open %s\n", filename);
|
||||
Unlock ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (writepcx)
|
||||
{
|
||||
WritePCXfile (file, this, palette);
|
||||
if (!screenshot_quiet)
|
||||
{
|
||||
Printf ("Captured %s\n", autoname.GetChars());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WritePNGfile (file, this, palette);
|
||||
if (!screenshot_quiet)
|
||||
{
|
||||
Printf ("Could not create screenshot.\n");
|
||||
}
|
||||
}
|
||||
fclose (file);
|
||||
Unlock ();
|
||||
}
|
||||
|
||||
CCMD (screenshot)
|
||||
|
|
290
src/m_png.cpp
290
src/m_png.cpp
|
@ -94,7 +94,6 @@ PNGHandle::~PNGHandle ()
|
|||
|
||||
static inline void MakeChunk (void *where, DWORD type, size_t len);
|
||||
static inline void StuffPalette (const PalEntry *from, BYTE *to);
|
||||
static bool StuffBitmap (const DCanvas *canvas, FILE *file);
|
||||
static bool WriteIDAT (FILE *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);
|
||||
|
@ -125,7 +124,8 @@ CVAR(Float, png_gamma, 0.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool M_CreatePNG (FILE *file, const DCanvas *canvas, const PalEntry *palette)
|
||||
bool M_CreatePNG (FILE *file, const BYTE *buffer, const PalEntry *palette,
|
||||
ESSType color_type, int width, int height, int pitch)
|
||||
{
|
||||
BYTE work[8 + // signature
|
||||
12+2*4+5 + // IHDR
|
||||
|
@ -135,14 +135,15 @@ bool M_CreatePNG (FILE *file, const DCanvas *canvas, const PalEntry *palette)
|
|||
IHDR *const ihdr = (IHDR *)&work[8 + 8];
|
||||
DWORD *const gama = (DWORD *)((BYTE *)ihdr + 2*4+5 + 12);
|
||||
BYTE *const plte = (BYTE *)gama + 4 + 12;
|
||||
size_t work_len;
|
||||
|
||||
sig[0] = MAKE_ID(137,'P','N','G');
|
||||
sig[1] = MAKE_ID(13,10,26,10);
|
||||
|
||||
ihdr->Width = BigLong (canvas->GetWidth ());
|
||||
ihdr->Height = BigLong (canvas->GetHeight ());
|
||||
ihdr->Width = BigLong(width);
|
||||
ihdr->Height = BigLong(height);
|
||||
ihdr->BitDepth = 8;
|
||||
ihdr->ColorType = 3;
|
||||
ihdr->ColorType = color_type == SS_PAL ? 3 : 2;
|
||||
ihdr->Compression = 0;
|
||||
ihdr->Filter = 0;
|
||||
ihdr->Interlace = 0;
|
||||
|
@ -152,13 +153,21 @@ bool M_CreatePNG (FILE *file, const DCanvas *canvas, const PalEntry *palette)
|
|||
*gama = BigLong (int (45454.5f * (png_gamma == 0.f ? Gamma : png_gamma)));
|
||||
MakeChunk (gama, MAKE_ID('g','A','M','A'), 4);
|
||||
|
||||
StuffPalette (palette, plte);
|
||||
MakeChunk (plte, MAKE_ID('P','L','T','E'), 256*3);
|
||||
if (color_type == SS_PAL)
|
||||
{
|
||||
StuffPalette (palette, plte);
|
||||
MakeChunk (plte, MAKE_ID('P','L','T','E'), 256*3);
|
||||
work_len = sizeof(work);
|
||||
}
|
||||
else
|
||||
{
|
||||
work_len = sizeof(work) - (12+256*3);
|
||||
}
|
||||
|
||||
if (fwrite (work, 1, sizeof(work), file) != sizeof(work))
|
||||
if (fwrite (work, 1, work_len, file) != work_len)
|
||||
return false;
|
||||
|
||||
return StuffBitmap (canvas, file);
|
||||
return M_SaveBitmap (buffer, color_type, width, height, pitch, file);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -707,7 +716,7 @@ static inline void MakeChunk (void *where, DWORD type, size_t len)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static inline void StuffPalette (const PalEntry *from, BYTE *to)
|
||||
static void StuffPalette (const PalEntry *from, BYTE *to)
|
||||
{
|
||||
for (int i = 256; i > 0; --i)
|
||||
{
|
||||
|
@ -721,27 +730,173 @@ static inline void StuffPalette (const PalEntry *from, BYTE *to)
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// StuffBitmap
|
||||
// CalcSum
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DWORD CalcSum(Byte *row, int len)
|
||||
{
|
||||
DWORD sum = 0;
|
||||
|
||||
while (len-- != 0)
|
||||
{
|
||||
sum += (char)*row++;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// SelectFilter
|
||||
//
|
||||
// Performs the heuristic recommended by the PNG spec to decide the
|
||||
// (hopefully) best filter to use for this row. To quate:
|
||||
//
|
||||
// Select the filter that gives the smallest sum of absolute values of
|
||||
// outputs. (Consider the output bytes as signed differences for this
|
||||
// test.)
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static int SelectFilter(Byte row[5][1 + MAXWIDTH*3], Byte prior[MAXWIDTH], int width)
|
||||
{
|
||||
#if 1
|
||||
// As it turns out, it seems no filtering is the best for Doom screenshots,
|
||||
// no matter what the heuristic might determine.
|
||||
return 0;
|
||||
#else
|
||||
DWORD sum;
|
||||
DWORD bestsum;
|
||||
int bestfilter;
|
||||
int x;
|
||||
|
||||
width *= 3;
|
||||
|
||||
// The first byte of each row holds the filter type, filled in by the caller.
|
||||
// However, the prior row does not contain a filter type, since it's always 0.
|
||||
|
||||
bestsum = 0;
|
||||
bestfilter = 0;
|
||||
|
||||
// None
|
||||
for (x = 1; x <= width; ++x)
|
||||
{
|
||||
bestsum += abs((char)row[0][x]);
|
||||
}
|
||||
|
||||
// Sub
|
||||
row[1][1] = row[0][1];
|
||||
row[1][2] = row[0][2];
|
||||
row[1][3] = row[0][3];
|
||||
sum = abs((char)row[0][1]) + abs((char)row[0][2]) + abs((char)row[0][3]);
|
||||
for (x = 4; x <= width; ++x)
|
||||
{
|
||||
row[1][x] = row[0][x] - row[0][x - 3];
|
||||
sum += abs((char)row[1][x]);
|
||||
if (sum >= bestsum)
|
||||
{ // This isn't going to be any better.
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sum < bestsum)
|
||||
{
|
||||
bestsum = sum;
|
||||
bestfilter = 1;
|
||||
}
|
||||
|
||||
// Up
|
||||
sum = 0;
|
||||
for (x = 1; x <= width; ++x)
|
||||
{
|
||||
row[2][x] = row[0][x] - prior[x - 1];
|
||||
sum += abs((char)row[2][x]);
|
||||
if (sum >= bestsum)
|
||||
{ // This isn't going to be any better.
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sum < bestsum)
|
||||
{
|
||||
bestsum = sum;
|
||||
bestfilter = 2;
|
||||
}
|
||||
|
||||
// Average
|
||||
row[3][1] = row[0][1] - prior[0] / 2;
|
||||
row[3][2] = row[0][2] - prior[1] / 2;
|
||||
row[3][3] = row[0][3] - prior[2] / 2;
|
||||
sum = abs((char)row[3][1]) + abs((char)row[3][2]) + abs((char)row[3][3]);
|
||||
for (x = 4; x <= width; ++x)
|
||||
{
|
||||
row[3][x] = row[0][x] - (row[0][x - 3] + prior[x - 1]) / 2;
|
||||
sum += (char)row[3][x];
|
||||
if (sum >= bestsum)
|
||||
{ // This isn't going to be any better.
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sum < bestsum)
|
||||
{
|
||||
bestsum = sum;
|
||||
bestfilter = 3;
|
||||
}
|
||||
|
||||
// Paeth
|
||||
row[4][1] = row[0][1] - prior[0];
|
||||
row[4][2] = row[0][2] - prior[1];
|
||||
row[4][3] = row[0][3] - prior[2];
|
||||
sum = abs((char)row[4][1]) + abs((char)row[4][2]) + abs((char)row[4][3]);
|
||||
for (x = 4; x <= width; ++x)
|
||||
{
|
||||
Byte a = row[0][x - 3];
|
||||
Byte b = prior[x - 1];
|
||||
Byte c = prior[x - 4];
|
||||
int p = a + b - c;
|
||||
int pa = abs(p - a);
|
||||
int pb = abs(p - b);
|
||||
int pc = abs(p - c);
|
||||
if (pa <= pb && pa <= pc)
|
||||
{
|
||||
row[4][x] = row[0][x] - a;
|
||||
}
|
||||
else if (pb <= pc)
|
||||
{
|
||||
row[4][x] = row[0][x] - b;
|
||||
}
|
||||
else
|
||||
{
|
||||
row[4][x] = row[0][x] - c;
|
||||
}
|
||||
sum += (char)row[4][x];
|
||||
if (sum >= bestsum)
|
||||
{ // This isn't going to be any better.
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sum < bestsum)
|
||||
{
|
||||
bestfilter = 4;
|
||||
}
|
||||
|
||||
return bestfilter;
|
||||
#endif
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// M_SaveBitmap
|
||||
//
|
||||
// Given a bitmap, creates one or more IDAT chunks in the given file.
|
||||
// Returns true on success.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static bool StuffBitmap (const DCanvas *canvas, FILE *file)
|
||||
{
|
||||
const int pitch = canvas->GetPitch();
|
||||
const int width = canvas->GetWidth();
|
||||
const int height = canvas->GetHeight();
|
||||
BYTE *from = canvas->GetBuffer();
|
||||
|
||||
return M_SaveBitmap(from, width, height, pitch, file);
|
||||
}
|
||||
|
||||
bool M_SaveBitmap(BYTE * from, int width, int height, int pitch, FILE *file)
|
||||
bool M_SaveBitmap(const BYTE *from, ESSType color_type, int width, int height, int pitch, FILE *file)
|
||||
{
|
||||
Byte prior[MAXWIDTH];
|
||||
Byte buffer[PNG_WRITE_SIZE];
|
||||
Byte zero = 0;
|
||||
Byte temprow[5][1 + MAXWIDTH*3];
|
||||
z_stream stream;
|
||||
int err;
|
||||
int y;
|
||||
|
@ -761,43 +916,74 @@ bool M_SaveBitmap(BYTE * from, int width, int height, int pitch, FILE *file)
|
|||
stream.next_out = buffer;
|
||||
stream.avail_out = sizeof(buffer);
|
||||
|
||||
while (y > 0 && err == Z_OK)
|
||||
temprow[0][0] = 0;
|
||||
temprow[1][0] = 1;
|
||||
temprow[2][0] = 2;
|
||||
temprow[3][0] = 3;
|
||||
temprow[4][0] = 4;
|
||||
|
||||
// Fill the prior row to 0 for RGB images. Paletted is always filter 0,
|
||||
// so it doesn't need this.
|
||||
if (color_type != SS_PAL)
|
||||
{
|
||||
y--;
|
||||
for (int i = 2; i && err == Z_OK; --i)
|
||||
memset(prior, 0, width * 3);
|
||||
}
|
||||
|
||||
while (y-- > 0 && err == Z_OK)
|
||||
{
|
||||
switch (color_type)
|
||||
{
|
||||
const int flushiness = (y == 0 && i == 1) ? Z_FINISH : 0;
|
||||
if (i == 2)
|
||||
{ // always use filter type 0
|
||||
stream.next_in = &zero;
|
||||
stream.avail_in = 1;
|
||||
}
|
||||
else
|
||||
case SS_PAL:
|
||||
memcpy(&temprow[0][1], from, width);
|
||||
// always use filter type 0 for paletted images
|
||||
stream.next_in = temprow[0];
|
||||
stream.avail_in = width + 1;
|
||||
break;
|
||||
|
||||
case SS_RGB:
|
||||
memcpy(&temprow[0][1], from, width*3);
|
||||
stream.next_in = temprow[SelectFilter(temprow, prior, width)];
|
||||
stream.avail_in = width * 3 + 1;
|
||||
break;
|
||||
|
||||
case SS_BGRA:
|
||||
for (int x = 0; x < width; ++x)
|
||||
{
|
||||
stream.next_in = from;
|
||||
stream.avail_in = width;
|
||||
from += pitch;
|
||||
temprow[0][x*3 + 1] = from[x*4 + 2];
|
||||
temprow[0][x*3 + 2] = from[x*4 + 1];
|
||||
temprow[0][x*3 + 3] = from[x*4];
|
||||
}
|
||||
err = deflate (&stream, flushiness);
|
||||
if (err != Z_OK)
|
||||
stream.next_in = temprow[SelectFilter(temprow, prior, width)];
|
||||
stream.avail_in = width * 3 + 1;
|
||||
break;
|
||||
}
|
||||
if (color_type != SS_PAL)
|
||||
{
|
||||
// Save this row for filter calculations on the next row.
|
||||
memcpy (prior, &temprow[0][1], stream.avail_in - 1);
|
||||
}
|
||||
|
||||
from += pitch;
|
||||
|
||||
err = deflate (&stream, (y == 0) ? Z_FINISH : 0);
|
||||
if (err != Z_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
while (stream.avail_out == 0)
|
||||
{
|
||||
if (!WriteIDAT (file, buffer, sizeof(buffer)))
|
||||
{
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
while (stream.avail_out == 0)
|
||||
stream.next_out = buffer;
|
||||
stream.avail_out = sizeof(buffer);
|
||||
if (stream.avail_in != 0)
|
||||
{
|
||||
if (!WriteIDAT (file, buffer, sizeof(buffer)))
|
||||
err = deflate (&stream, (y == 0) ? Z_FINISH : 0);
|
||||
if (err != Z_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
stream.next_out = buffer;
|
||||
stream.avail_out = sizeof(buffer);
|
||||
if (stream.avail_in != 0)
|
||||
{
|
||||
err = deflate (&stream, flushiness);
|
||||
if (err != Z_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,8 @@
|
|||
// 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 DCanvas *canvas, const PalEntry *pal);
|
||||
bool M_CreatePNG (FILE *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);
|
||||
|
@ -53,7 +54,7 @@ bool M_AppendPNGText (FILE *file, const char *keyword, const char *text);
|
|||
// Appends the IEND chunk to a PNG file.
|
||||
bool M_FinishPNG (FILE *file);
|
||||
|
||||
bool M_SaveBitmap(BYTE * from, int width, int height, int pitch, FILE *file);
|
||||
bool M_SaveBitmap(const BYTE *from, ESSType color_type, int width, int height, int pitch, FILE *file);
|
||||
|
||||
// PNG Reading --------------------------------------------------------------
|
||||
|
||||
|
|
301
src/v_video.cpp
301
src/v_video.cpp
|
@ -184,6 +184,12 @@ void V_MarkRect (int x, int y, int width, int height)
|
|||
|
||||
DCanvas *DCanvas::CanvasChain = NULL;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DCanvas Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DCanvas::DCanvas (int _width, int _height)
|
||||
{
|
||||
// Init member vars
|
||||
|
@ -198,6 +204,12 @@ DCanvas::DCanvas (int _width, int _height)
|
|||
CanvasChain = this;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DCanvas Destructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DCanvas::~DCanvas ()
|
||||
{
|
||||
// Remove from list of active canvases
|
||||
|
@ -218,6 +230,12 @@ DCanvas::~DCanvas ()
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DCanvas :: IsValid
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool DCanvas::IsValid ()
|
||||
{
|
||||
// A nun-subclassed DCanvas is never valid
|
||||
|
@ -255,8 +273,14 @@ void DCanvas::FlatFill (int left, int top, int right, int bottom, FTexture *src,
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DCanvas :: Clear
|
||||
//
|
||||
// Set an area to a specified color.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
// [RH] Set an area to a specified color
|
||||
void DCanvas::Clear (int left, int top, int right, int bottom, int palcolor, uint32 color)
|
||||
{
|
||||
int x, y;
|
||||
|
@ -298,6 +322,15 @@ void DCanvas::Clear (int left, int top, int right, int bottom, int palcolor, uin
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DCanvas :: Dim
|
||||
//
|
||||
// Applies a colored overlay to the entire screen, with the opacity
|
||||
// determined by the dimamount cvar.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DCanvas::Dim (PalEntry color)
|
||||
{
|
||||
PalEntry dimmer;
|
||||
|
@ -320,6 +353,14 @@ void DCanvas::Dim (PalEntry color)
|
|||
Dim (dimmer, amount, 0, 0, Width, Height);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DCanvas :: Dim
|
||||
//
|
||||
// Applies a colored overlay to an area of the screen.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DCanvas::Dim (PalEntry color, float damount, int x1, int y1, int w, int h)
|
||||
{
|
||||
if (damount == 0.f)
|
||||
|
@ -359,11 +400,59 @@ void DCanvas::Dim (PalEntry color, float damount, int x1, int y1, int w, int h)
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DCanvas :: UsesColormap
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool DCanvas::UsesColormap() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DCanvas :: GetScreenshotBuffer
|
||||
//
|
||||
// Returns a buffer containing the most recently displayed frame. The
|
||||
// width and height of this buffer are the same as the canvas.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DCanvas::GetScreenshotBuffer(const BYTE *&buffer, int &pitch, ESSType &color_type)
|
||||
{
|
||||
Lock(true);
|
||||
buffer = GetBuffer();
|
||||
pitch = GetPitch();
|
||||
color_type = SS_PAL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DCanvas :: ReleaseScreenshotBuffer
|
||||
//
|
||||
// Releases the buffer obtained through GetScreenshotBuffer. These calls
|
||||
// must not be nested.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DCanvas::ReleaseScreenshotBuffer()
|
||||
{
|
||||
Unlock();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// V_GetColorFromString
|
||||
//
|
||||
// Passed a string of the form "#RGB", "#RRGGBB", "R G B", or "RR GG BB",
|
||||
// returns a number representing that color. If palette is non-NULL, the
|
||||
// index of the best match in the palette is returned, otherwise the
|
||||
// RRGGBB value is returned directly.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int V_GetColorFromString (const DWORD *palette, const char *cstr)
|
||||
{
|
||||
int c[3], i, p;
|
||||
|
@ -434,11 +523,20 @@ int V_GetColorFromString (const DWORD *palette, const char *cstr)
|
|||
}
|
||||
}
|
||||
if (palette)
|
||||
return ColorMatcher.Pick (c[0]>>8, c[1]>>8, c[2]>>8);
|
||||
return ColorMatcher.Pick (c[0], c[1], c[2]);
|
||||
else
|
||||
return MAKERGB(c[0], c[1], c[2]);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// V_GetColorStringByName
|
||||
//
|
||||
// Searches for the given color name in x11r6rgb.txt and returns an
|
||||
// HTML-ish "#RRGGBB" string for it if found or the empty string if not.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString V_GetColorStringByName (const char *name)
|
||||
{
|
||||
FMemLump rgbNames;
|
||||
|
@ -520,6 +618,14 @@ FString V_GetColorStringByName (const char *name)
|
|||
return FString();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// V_GetColor
|
||||
//
|
||||
// Works like V_GetColorFromString(), but also understands X11 color names.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int V_GetColor (const DWORD *palette, const char *str)
|
||||
{
|
||||
FString string = V_GetColorStringByName (str);
|
||||
|
@ -536,7 +642,14 @@ int V_GetColor (const DWORD *palette, const char *str)
|
|||
return res;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// BuildTransTable
|
||||
//
|
||||
// Build the tables necessary for blending
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void BuildTransTable (const PalEntry *palette)
|
||||
{
|
||||
int r, g, b;
|
||||
|
@ -570,6 +683,12 @@ static void BuildTransTable (const PalEntry *palette)
|
|||
Col2RGB8_LessPrecision[64] = Col2RGB8[64];
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DCanvas :: CalcGamma
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DCanvas::CalcGamma (float gamma, BYTE gammalookup[256])
|
||||
{
|
||||
// I found this formula on the web at
|
||||
|
@ -585,6 +704,14 @@ void DCanvas::CalcGamma (float gamma, BYTE gammalookup[256])
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DSimpleCanvas Constructor
|
||||
//
|
||||
// A simple canvas just holds a buffer in main memory.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DSimpleCanvas::DSimpleCanvas (int width, int height)
|
||||
: DCanvas (width, height)
|
||||
{
|
||||
|
@ -627,6 +754,12 @@ DSimpleCanvas::DSimpleCanvas (int width, int height)
|
|||
memset (MemBuffer, 0, Pitch * height);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DSimpleCanvas Destructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DSimpleCanvas::~DSimpleCanvas ()
|
||||
{
|
||||
if (MemBuffer != NULL)
|
||||
|
@ -636,11 +769,23 @@ DSimpleCanvas::~DSimpleCanvas ()
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DSimpleCanvas :: IsValid
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool DSimpleCanvas::IsValid ()
|
||||
{
|
||||
return (MemBuffer != NULL);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DSimpleCanvas :: Lock
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool DSimpleCanvas::Lock ()
|
||||
{
|
||||
if (LockCount == 0)
|
||||
|
@ -651,6 +796,12 @@ bool DSimpleCanvas::Lock ()
|
|||
return false; // System surfaces are never lost
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DSimpleCanvas :: Unlock
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DSimpleCanvas::Unlock ()
|
||||
{
|
||||
if (--LockCount <= 0)
|
||||
|
@ -660,6 +811,15 @@ void DSimpleCanvas::Unlock ()
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DFrameBuffer Constructor
|
||||
//
|
||||
// A frame buffer canvas is the most common and represents the image that
|
||||
// gets drawn to the screen.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
DFrameBuffer::DFrameBuffer (int width, int height)
|
||||
: DSimpleCanvas (width, height)
|
||||
{
|
||||
|
@ -667,6 +827,14 @@ DFrameBuffer::DFrameBuffer (int width, int height)
|
|||
Accel2D = false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DFrameBuffer :: DrawRateStuff
|
||||
//
|
||||
// Draws the fps counter, dot ticker, and palette debug.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFrameBuffer::DrawRateStuff ()
|
||||
{
|
||||
// Draws frame time and cumulative fps
|
||||
|
@ -742,6 +910,14 @@ void DFrameBuffer::DrawRateStuff ()
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FPaleteTester Constructor
|
||||
//
|
||||
// This is just a 16x16 image with every possible color value.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FPaletteTester::FPaletteTester()
|
||||
{
|
||||
Width = 16;
|
||||
|
@ -754,11 +930,23 @@ FPaletteTester::FPaletteTester()
|
|||
MakeTexture();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FPaletteTester :: CheckModified
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FPaletteTester::CheckModified()
|
||||
{
|
||||
return CurTranslation != WantTranslation;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FPaletteTester :: SetTranslation
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FPaletteTester::SetTranslation(int num)
|
||||
{
|
||||
if (num >= 1 && num <= 9)
|
||||
|
@ -767,10 +955,22 @@ void FPaletteTester::SetTranslation(int num)
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FPaletteTester :: Unload
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FPaletteTester::Unload()
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FPaletteTester :: GetColumn
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
const BYTE *FPaletteTester::GetColumn (unsigned int column, const Span **spans_out)
|
||||
{
|
||||
if (CurTranslation != WantTranslation)
|
||||
|
@ -785,6 +985,12 @@ const BYTE *FPaletteTester::GetColumn (unsigned int column, const Span **spans_o
|
|||
return Pixels + column*16;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FPaletteTester :: GetPixels
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
const BYTE *FPaletteTester::GetPixels ()
|
||||
{
|
||||
if (CurTranslation != WantTranslation)
|
||||
|
@ -794,6 +1000,12 @@ const BYTE *FPaletteTester::GetPixels ()
|
|||
return Pixels;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FPaletteTester :: MakeTexture
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FPaletteTester::MakeTexture()
|
||||
{
|
||||
int i, j, k, t;
|
||||
|
@ -814,6 +1026,15 @@ void FPaletteTester::MakeTexture()
|
|||
CurTranslation = t;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DFrameBuffer :: CopyFromBuff
|
||||
//
|
||||
// Copies pixels from main memory to video memory. This is only used by
|
||||
// DDrawFB.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFrameBuffer::CopyFromBuff (BYTE *src, int srcPitch, int width, int height, BYTE *dest)
|
||||
{
|
||||
if (Pitch == width && Pitch == Width && srcPitch == width)
|
||||
|
@ -831,46 +1052,122 @@ void DFrameBuffer::CopyFromBuff (BYTE *src, int srcPitch, int width, int height,
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DFrameBuffer :: SetVSync
|
||||
//
|
||||
// Turns vertical sync on and off, if supported.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFrameBuffer::SetVSync (bool vsync)
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DFrameBuffer :: SetBlendingRect
|
||||
//
|
||||
// Defines the area of the screen containing the 3D view.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFrameBuffer::SetBlendingRect (int x1, int y1, int x2, int y2)
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DFrameBuffer :: Begin2D
|
||||
//
|
||||
// Signal that 3D rendering is complete, and the rest of the operations on
|
||||
// the canvas until Unlock() will be 2D ones.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool DFrameBuffer::Begin2D (bool copy3d)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DFrameBuffer :: CreateTexture
|
||||
//
|
||||
// Creates a native texture for a game texture, if supported.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FNativeTexture *DFrameBuffer::CreateTexture(FTexture *gametex, bool wrapping)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DFrameBuffer :: CreatePalette
|
||||
//
|
||||
// Creates a native palette from a remap table, if supported.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FNativePalette *DFrameBuffer::CreatePalette(FRemapTable *remap)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DFrameBuffer :: WipeStartScreen
|
||||
//
|
||||
// Grabs a copy of the screen currently displayed to serve as the initial
|
||||
// frame of a screen wipe. Also determines which screenwipe will be
|
||||
// performed.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool DFrameBuffer::WipeStartScreen(int type)
|
||||
{
|
||||
return wipe_StartScreen(type);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DFrameBuffer :: WipeEndScreen
|
||||
//
|
||||
// Grabs a copy of the most-recently drawn, but not yet displayed, screen
|
||||
// to serve as the final frame of a screen wipe.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFrameBuffer::WipeEndScreen()
|
||||
{
|
||||
wipe_EndScreen();
|
||||
Unlock();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DFrameBuffer :: WipeDo
|
||||
//
|
||||
// Draws one frame of a screenwipe. Should be called no more than 35
|
||||
// times per second. If called less than that, ticks indicates how many
|
||||
// ticks have passed since the last call.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool DFrameBuffer::WipeDo(int ticks)
|
||||
{
|
||||
Lock(true);
|
||||
return wipe_ScreenWipe(ticks);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DFrameBuffer :: WipeCleanup
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DFrameBuffer::WipeCleanup()
|
||||
{
|
||||
wipe_Cleanup();
|
||||
|
|
|
@ -117,13 +117,18 @@ enum
|
|||
HUD_HorizCenter
|
||||
};
|
||||
|
||||
// Screenshot buffer image data types
|
||||
enum ESSType
|
||||
{
|
||||
SS_PAL,
|
||||
SS_RGB,
|
||||
SS_BGRA
|
||||
};
|
||||
|
||||
//
|
||||
// VIDEO
|
||||
//
|
||||
// [RH] Made screens more implementation-independant:
|
||||
// This layer isn't really necessary, and it would be nice to remove it, I think.
|
||||
// But ZDoom is now built around it so much, I'll probably just leave it.
|
||||
//
|
||||
class DCanvas : public DObject
|
||||
{
|
||||
|
@ -178,11 +183,13 @@ public:
|
|||
// Can be overridden so that the colormaps for sector color/fade won't be built.
|
||||
virtual bool UsesColormap() const;
|
||||
|
||||
// software renderer always returns true but other renderers may not want to implement PCX.
|
||||
bool CanWritePCX();
|
||||
// Retrieves a buffer containing image data for a screenshot.
|
||||
// Hint: Pitch can be negative for upside-down images, in which case buffer
|
||||
// points to the last row in the buffer, which will be the first row output.
|
||||
virtual void GetScreenshotBuffer(const BYTE *&buffer, int &pitch, ESSType &color_type);
|
||||
|
||||
// Saves canvas to a file
|
||||
void Save(const char *filename, bool writepcx);
|
||||
// Releases the screenshot buffer.
|
||||
virtual void ReleaseScreenshotBuffer();
|
||||
|
||||
// Text drawing functions -----------------------------------------------
|
||||
|
||||
|
|
|
@ -227,6 +227,8 @@ D3DFB::D3DFB (int width, int height, bool fullscreen)
|
|||
FBTexture = NULL;
|
||||
TempRenderTexture = NULL;
|
||||
InitialWipeScreen = NULL;
|
||||
ScreenshotTexture = NULL;
|
||||
ScreenshotSurface = NULL;
|
||||
FinalWipeScreen = NULL;
|
||||
PaletteTexture = NULL;
|
||||
StencilPaletteTexture = NULL;
|
||||
|
@ -439,6 +441,8 @@ void D3DFB::ReleaseResources ()
|
|||
KillNativeTexs();
|
||||
KillNativePals();
|
||||
ReleaseDefaultPoolItems();
|
||||
SAFE_RELEASE( ScreenshotSurface );
|
||||
SAFE_RELEASE( ScreenshotTexture );
|
||||
SAFE_RELEASE( PaletteTexture );
|
||||
SAFE_RELEASE( StencilPaletteTexture );
|
||||
SAFE_RELEASE( ShadedPaletteTexture );
|
||||
|
@ -1087,6 +1091,161 @@ void D3DFB::SetBlendingRect(int x1, int y1, int x2, int y2)
|
|||
BlendingRect.bottom = y2;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// D3DFB :: GetScreenshotBuffer
|
||||
//
|
||||
// Returns a pointer into a surface holding the current screen data.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void D3DFB::GetScreenshotBuffer(const BYTE *&buffer, int &pitch, ESSType &color_type)
|
||||
{
|
||||
D3DLOCKED_RECT lrect;
|
||||
|
||||
if (!test2d)
|
||||
{
|
||||
Super::GetScreenshotBuffer(buffer, pitch, color_type);
|
||||
return;
|
||||
}
|
||||
buffer = NULL;
|
||||
if ((ScreenshotTexture = GetCurrentScreen()) != NULL)
|
||||
{
|
||||
if (FAILED(ScreenshotTexture->GetSurfaceLevel(0, &ScreenshotSurface)))
|
||||
{
|
||||
ScreenshotTexture->Release();
|
||||
ScreenshotTexture = NULL;
|
||||
}
|
||||
else if (FAILED(ScreenshotSurface->LockRect(&lrect, NULL, D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK)))
|
||||
{
|
||||
ScreenshotSurface->Release();
|
||||
ScreenshotSurface = NULL;
|
||||
ScreenshotTexture->Release();
|
||||
ScreenshotTexture = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = (const BYTE *)lrect.pBits + lrect.Pitch * LBOffsetI;
|
||||
pitch = lrect.Pitch;
|
||||
color_type = SS_BGRA;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// D3DFB :: ReleaseScreenshotBuffer
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void D3DFB::ReleaseScreenshotBuffer()
|
||||
{
|
||||
if (LockCount > 0)
|
||||
{
|
||||
Super::ReleaseScreenshotBuffer();
|
||||
}
|
||||
if (ScreenshotSurface != NULL)
|
||||
{
|
||||
ScreenshotSurface->UnlockRect();
|
||||
ScreenshotSurface->Release();
|
||||
ScreenshotSurface = NULL;
|
||||
}
|
||||
SAFE_RELEASE( ScreenshotTexture );
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// D3DFB :: GetCurrentScreen
|
||||
//
|
||||
// Returns a texture containing the pixels currently visible on-screen.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
IDirect3DTexture9 *D3DFB::GetCurrentScreen()
|
||||
{
|
||||
IDirect3DTexture9 *tex;
|
||||
IDirect3DSurface9 *tsurf, *surf;
|
||||
D3DSURFACE_DESC desc;
|
||||
|
||||
if (Windowed)
|
||||
{
|
||||
// The texture we read into must have the same pixel format as
|
||||
// the TempRenderTexture.
|
||||
if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &tsurf)))
|
||||
{
|
||||
if (FAILED(tsurf->GetDesc(&desc)))
|
||||
{
|
||||
tsurf->Release();
|
||||
return NULL;
|
||||
}
|
||||
tsurf->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SUCCEEDED(D3DDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &tsurf)))
|
||||
{
|
||||
if (FAILED(tsurf->GetDesc(&desc)))
|
||||
{
|
||||
tsurf->Release();
|
||||
return NULL;
|
||||
}
|
||||
tsurf->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
// GetFrontBufferData works only with this format
|
||||
desc.Format = D3DFMT_A8R8G8B8;
|
||||
}
|
||||
|
||||
if (FAILED(D3DDevice->CreateTexture(desc.Width, desc.Height, 1, 0,
|
||||
desc.Format, D3DPOOL_SYSTEMMEM, &tex, NULL)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (FAILED(tex->GetSurfaceLevel(0, &surf)))
|
||||
{
|
||||
tex->Release();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!Windowed)
|
||||
{
|
||||
if (FAILED(D3DDevice->GetFrontBufferData(0, surf)))
|
||||
{
|
||||
surf->Release();
|
||||
tex->Release();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &tsurf)))
|
||||
{
|
||||
if (FAILED(D3DDevice->GetRenderTargetData(tsurf, surf)))
|
||||
{
|
||||
tsurf->Release();
|
||||
tex->Release();
|
||||
return NULL;
|
||||
}
|
||||
tsurf->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
tex->Release();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
surf->Release();
|
||||
return tex;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/* 2D Stuff */
|
||||
/**************************************************************************/
|
||||
|
@ -1435,40 +1594,43 @@ void D3DFB::PackingTexture::AllocateImage(D3DFB::PackedTexture *box, int w, int
|
|||
box->Prev = &UsedList;
|
||||
|
||||
// If we didn't use the whole box, split the remainder into the empty list.
|
||||
#if 1
|
||||
// Split like this:
|
||||
// +---+------+
|
||||
// |###| |
|
||||
// +---+------+
|
||||
// | |
|
||||
// | |
|
||||
// +----------+
|
||||
// Empirical evidence indicates that this gives the best utilization.
|
||||
if (box->Area.bottom < start.bottom)
|
||||
|
||||
if (box->Area.bottom + 7 < start.bottom && box->Area.right + 7 < start.right)
|
||||
{
|
||||
AddEmptyBox(start.left, box->Area.bottom, start.right, start.bottom);
|
||||
// Split like this:
|
||||
// +---+------+
|
||||
// |###| |
|
||||
// +---+------+
|
||||
// | |
|
||||
// | |
|
||||
// +----------+
|
||||
if (box->Area.bottom < start.bottom)
|
||||
{
|
||||
AddEmptyBox(start.left, box->Area.bottom, start.right, start.bottom);
|
||||
}
|
||||
if (box->Area.right < start.right)
|
||||
{
|
||||
AddEmptyBox(box->Area.right, start.top, start.right, box->Area.bottom);
|
||||
}
|
||||
}
|
||||
if (box->Area.right < start.right)
|
||||
else
|
||||
{
|
||||
AddEmptyBox(box->Area.right, start.top, start.right, box->Area.bottom);
|
||||
// Split like this:
|
||||
// +---+------+
|
||||
// |###| |
|
||||
// +---+ |
|
||||
// | | |
|
||||
// | | |
|
||||
// +---+------+
|
||||
if (box->Area.bottom < start.bottom)
|
||||
{
|
||||
AddEmptyBox(start.left, box->Area.bottom, box->Area.right, start.bottom);
|
||||
}
|
||||
if (box->Area.right < start.right)
|
||||
{
|
||||
AddEmptyBox(box->Area.right, start.top, start.right, start.bottom);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// Split like this:
|
||||
// +---+------+
|
||||
// |###| |
|
||||
// +---+ |
|
||||
// | | |
|
||||
// | | |
|
||||
// +---+------+
|
||||
if (box->Area.bottom < start.bottom)
|
||||
{
|
||||
AddEmptyBox(start.left, box->Area.bottom, box->Area.right, start.bottom);
|
||||
}
|
||||
if (box->Area.right < start.right)
|
||||
{
|
||||
AddEmptyBox(box->Area.right, start.top, start.right, start.bottom);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -135,7 +135,7 @@ EXTERN_CVAR(Bool, test2d)
|
|||
|
||||
bool D3DFB::WipeStartScreen(int type)
|
||||
{
|
||||
IDirect3DSurface9 *surf, *tsurf;
|
||||
IDirect3DSurface9 *tsurf;
|
||||
D3DSURFACE_DESC desc;
|
||||
|
||||
if (!test2d)
|
||||
|
@ -161,106 +161,39 @@ bool D3DFB::WipeStartScreen(int type)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (Windowed)
|
||||
{
|
||||
// The InitialWipeScreen must have the same pixel format as
|
||||
// the TempRenderTexture.
|
||||
if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &tsurf)))
|
||||
{
|
||||
if (FAILED(tsurf->GetDesc(&desc)))
|
||||
{
|
||||
tsurf->Release();
|
||||
return false;
|
||||
}
|
||||
tsurf->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SUCCEEDED(D3DDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &tsurf)))
|
||||
{
|
||||
if (FAILED(tsurf->GetDesc(&desc)))
|
||||
{
|
||||
tsurf->Release();
|
||||
return false;
|
||||
}
|
||||
tsurf->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// GetFrontBufferData works only with this format
|
||||
desc.Format = D3DFMT_A8R8G8B8;
|
||||
}
|
||||
InitialWipeScreen = GetCurrentScreen();
|
||||
|
||||
if (FAILED(D3DDevice->CreateTexture(desc.Width, desc.Height, 1, 0,
|
||||
desc.Format, D3DPOOL_SYSTEMMEM, &InitialWipeScreen, NULL)))
|
||||
{
|
||||
InitialWipeScreen = NULL;
|
||||
return false;
|
||||
}
|
||||
if (FAILED(InitialWipeScreen->GetSurfaceLevel(0, &surf)))
|
||||
{
|
||||
InitialWipeScreen->Release();
|
||||
InitialWipeScreen = NULL;
|
||||
return false;
|
||||
}
|
||||
if (!Windowed)
|
||||
{
|
||||
if (FAILED(D3DDevice->GetFrontBufferData(0, surf)))
|
||||
{
|
||||
surf->Release();
|
||||
InitialWipeScreen->Release();
|
||||
InitialWipeScreen = NULL;
|
||||
return false;
|
||||
}
|
||||
FinalWipeScreen = TempRenderTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &tsurf)))
|
||||
{
|
||||
if (FAILED(D3DDevice->GetRenderTargetData(tsurf, surf)))
|
||||
{
|
||||
tsurf->Release();
|
||||
InitialWipeScreen->Release();
|
||||
InitialWipeScreen = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
InitialWipeScreen->Release();
|
||||
InitialWipeScreen = NULL;
|
||||
return false;
|
||||
}
|
||||
// Create another texture to copy the final wipe screen to so
|
||||
// we can still gamma correct the wipe. Since this is just for
|
||||
// gamma correction, it's okay to fail (though not desirable.)
|
||||
if (GammaFixerShader != NULL && Gamma != 1)
|
||||
{
|
||||
if (FAILED(tsurf->GetDesc(&desc)) ||
|
||||
FAILED(D3DDevice->CreateTexture(desc.Width, desc.Height,
|
||||
1, D3DUSAGE_RENDERTARGET, desc.Format, D3DPOOL_DEFAULT,
|
||||
&FinalWipeScreen, NULL)))
|
||||
if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &tsurf)))
|
||||
{
|
||||
FinalWipeScreen = TempRenderTexture;
|
||||
if (FAILED(tsurf->GetDesc(&desc)) ||
|
||||
FAILED(D3DDevice->CreateTexture(desc.Width, desc.Height,
|
||||
1, D3DUSAGE_RENDERTARGET, desc.Format, D3DPOOL_DEFAULT,
|
||||
&FinalWipeScreen, NULL)))
|
||||
{
|
||||
FinalWipeScreen = TempRenderTexture;
|
||||
}
|
||||
tsurf->Release();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FinalWipeScreen = TempRenderTexture;
|
||||
}
|
||||
tsurf->Release();
|
||||
}
|
||||
surf->Release();
|
||||
// Even fullscreen will render to the TempRenderTexture, so we can have
|
||||
// a copy of the new screen readily available.
|
||||
|
||||
// Make even fullscreen model render to the TempRenderTexture, so
|
||||
// we can have a copy of the new screen readily available.
|
||||
GatheringWipeScreen = true;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -237,6 +237,8 @@ public:
|
|||
void Blank ();
|
||||
bool PaintToWindow ();
|
||||
void SetVSync (bool vsync);
|
||||
void GetScreenshotBuffer(const BYTE *&buffer, int &pitch, ESSType &color_type);
|
||||
void ReleaseScreenshotBuffer();
|
||||
void SetBlendingRect (int x1, int y1, int x2, int y2);
|
||||
bool Begin2D (bool copy3d);
|
||||
FNativeTexture *CreateTexture (FTexture *gametex, bool wrapping);
|
||||
|
@ -297,6 +299,7 @@ private:
|
|||
void FillPresentParameters (D3DPRESENT_PARAMETERS *pp, bool fullscreen, bool vsync);
|
||||
void CalcFullscreenCoords (FBVERTEX verts[4], bool viewarea_only, D3DCOLOR color0, D3DCOLOR color1) const;
|
||||
bool Reset();
|
||||
IDirect3DTexture9 *GetCurrentScreen();
|
||||
void ReleaseDefaultPoolItems();
|
||||
void KillNativePals();
|
||||
void KillNativeTexs();
|
||||
|
@ -360,6 +363,8 @@ private:
|
|||
IDirect3DTexture9 *PaletteTexture;
|
||||
IDirect3DTexture9 *StencilPaletteTexture;
|
||||
IDirect3DTexture9 *ShadedPaletteTexture;
|
||||
IDirect3DTexture9 *ScreenshotTexture;
|
||||
IDirect3DSurface9 *ScreenshotSurface;
|
||||
|
||||
IDirect3DVertexBuffer9 *VertexBuffer;
|
||||
FBVERTEX *VertexData;
|
||||
|
|
Loading…
Reference in a new issue