mirror of https://github.com/ZDoom/gzdoom.git
- 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
|
@ -1,11 +1,15 @@
|
||||||
January 11, 2008
|
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
|
- For compatibility with the software renderer, D3DFB::DrawTextureV needs to
|
||||||
truncate the coordinates to integers before sending them to the hardware.
|
truncate the coordinates to integers before sending them to the hardware.
|
||||||
Otherwise, there can be one pixel gaps compared to the software renderer,
|
Otherwise, there can be one pixel gaps compared to the software renderer,
|
||||||
because the hardware is rounding to nearest but the software renderer is
|
because the hardware is rounding to nearest but the software renderer is
|
||||||
simply truncating the fractional part of the coordinate. This is the real
|
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
|
cause of the gap above the status bar at 1152x864 (and another gap to the
|
||||||
to the left of the status bar at 800x500).
|
left of the status bar at 800x500).
|
||||||
- Fixed: When D3DFB::DrawTextureV had to clip a tile, it adjusted the
|
- Fixed: When D3DFB::DrawTextureV had to clip a tile, it adjusted the
|
||||||
texture coordinates erroneously, still using the old calculations from
|
texture coordinates erroneously, still using the old calculations from
|
||||||
before texture packing was implemented.
|
before texture packing was implemented.
|
||||||
|
|
|
@ -1977,7 +1977,7 @@ static void PutSavePic (FILE *file, int width, int height)
|
||||||
P_CheckPlayerSprites();
|
P_CheckPlayerSprites();
|
||||||
R_RenderViewToCanvas (players[consoleplayer].mo, pic, 0, 0, width, height);
|
R_RenderViewToCanvas (players[consoleplayer].mo, pic, 0, 0, width, height);
|
||||||
screen->GetFlashedPalette (palette);
|
screen->GetFlashedPalette (palette);
|
||||||
M_CreatePNG (file, pic, palette);
|
M_CreatePNG (file, pic->GetBuffer(), palette, SS_PAL, width, height, pic->GetPitch());
|
||||||
pic->Unlock ();
|
pic->Unlock ();
|
||||||
delete pic;
|
delete pic;
|
||||||
}
|
}
|
||||||
|
|
145
src/m_misc.cpp
145
src/m_misc.cpp
|
@ -432,24 +432,21 @@ typedef struct
|
||||||
//
|
//
|
||||||
// WritePCXfile
|
// 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 x, y;
|
||||||
int runlen;
|
int runlen;
|
||||||
|
int bytes_per_row_minus_one;
|
||||||
BYTE color;
|
BYTE color;
|
||||||
pcx_t pcx;
|
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.manufacturer = 10; // PCX id
|
||||||
pcx.version = 5; // 256 color
|
pcx.version = 5; // 256 (or more) colors
|
||||||
pcx.encoding = 1;
|
pcx.encoding = 1;
|
||||||
pcx.bits_per_pixel = 8; // 256 color
|
pcx.bits_per_pixel = 8; // 256 (or more) colors
|
||||||
pcx.xmin = 0;
|
pcx.xmin = 0;
|
||||||
pcx.ymin = 0;
|
pcx.ymin = 0;
|
||||||
pcx.xmax = LittleShort(width-1);
|
pcx.xmax = LittleShort(width-1);
|
||||||
|
@ -458,20 +455,52 @@ void WritePCXfile (FILE *file, const DCanvas *canvas, const PalEntry *palette)
|
||||||
pcx.vdpi = LittleShort(75);
|
pcx.vdpi = LittleShort(75);
|
||||||
memset (pcx.palette, 0, sizeof(pcx.palette));
|
memset (pcx.palette, 0, sizeof(pcx.palette));
|
||||||
pcx.reserved = 0;
|
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.bytes_per_line = width + (width & 1);
|
||||||
pcx.palette_type = 1; // not a grey scale
|
pcx.palette_type = 1; // not a grey scale
|
||||||
memset (pcx.filler, 0, sizeof(pcx.filler));
|
memset (pcx.filler, 0, sizeof(pcx.filler));
|
||||||
|
|
||||||
fwrite (&pcx, 128, 1, file);
|
fwrite (&pcx, 128, 1, file);
|
||||||
|
|
||||||
|
bytes_per_row_minus_one = ((color_type == SS_PAL) ? width : width * 3) - 1;
|
||||||
|
|
||||||
// pack the image
|
// pack the image
|
||||||
for (y = height; y > 0; y--)
|
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++;
|
color = *data++;
|
||||||
runlen = 1;
|
runlen = 1;
|
||||||
|
|
||||||
for (x = width - 1; x > 0; x--)
|
for (x = bytes_per_row_minus_one; x > 0; x--)
|
||||||
{
|
{
|
||||||
if (*data == color)
|
if (*data == color)
|
||||||
{
|
{
|
||||||
|
@ -522,26 +551,28 @@ void WritePCXfile (FILE *file, const DCanvas *canvas, const PalEntry *palette)
|
||||||
|
|
||||||
if (width & 1)
|
if (width & 1)
|
||||||
putc (0, file);
|
putc (0, file);
|
||||||
|
|
||||||
data += pitch - width;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// write the palette
|
// write the palette
|
||||||
putc (12, file); // palette ID byte
|
if (color_type == SS_PAL)
|
||||||
for (x = 0; x < 256; x++, palette++)
|
|
||||||
{
|
{
|
||||||
putc (palette->r, file);
|
putc (12, file); // palette ID byte
|
||||||
putc (palette->g, file);
|
for (x = 0; x < 256; x++, palette++)
|
||||||
putc (palette->b, file);
|
{
|
||||||
|
putc (palette->r, file);
|
||||||
|
putc (palette->g, file);
|
||||||
|
putc (palette->b, file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// WritePNGfile
|
// 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_AppendPNGText (file, "Software", GAMENAME DOTVERSIONSTR) ||
|
||||||
!M_FinishPNG (file))
|
!M_FinishPNG (file))
|
||||||
{
|
{
|
||||||
|
@ -572,8 +603,9 @@ static bool FindFreeName (FString &fullname, const char *extension)
|
||||||
|
|
||||||
void M_ScreenShot (const char *filename)
|
void M_ScreenShot (const char *filename)
|
||||||
{
|
{
|
||||||
|
FILE *file;
|
||||||
FString autoname;
|
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
|
// find a file name to save it to
|
||||||
if (filename == NULL || filename[0] == '\0')
|
if (filename == NULL || filename[0] == '\0')
|
||||||
|
@ -614,46 +646,51 @@ void M_ScreenShot (const char *filename)
|
||||||
CreatePath(screenshot_dir);
|
CreatePath(screenshot_dir);
|
||||||
|
|
||||||
// save the screenshot
|
// 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()
|
if (color_type == SS_PAL)
|
||||||
{
|
{
|
||||||
return true;
|
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)
|
if (!screenshot_quiet)
|
||||||
{
|
{
|
||||||
FILE *file;
|
Printf ("Captured %s\n", autoname.GetChars());
|
||||||
|
}
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WritePNGfile (file, this, palette);
|
if (!screenshot_quiet)
|
||||||
|
{
|
||||||
|
Printf ("Could not create screenshot.\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fclose (file);
|
|
||||||
Unlock ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CCMD (screenshot)
|
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 MakeChunk (void *where, DWORD type, size_t len);
|
||||||
static inline void StuffPalette (const PalEntry *from, BYTE *to);
|
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 bool WriteIDAT (FILE *file, const BYTE *data, int len);
|
||||||
static void UnfilterRow (int width, BYTE *dest, BYTE *stream, BYTE *prev, int bpp);
|
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);
|
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
|
BYTE work[8 + // signature
|
||||||
12+2*4+5 + // IHDR
|
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];
|
IHDR *const ihdr = (IHDR *)&work[8 + 8];
|
||||||
DWORD *const gama = (DWORD *)((BYTE *)ihdr + 2*4+5 + 12);
|
DWORD *const gama = (DWORD *)((BYTE *)ihdr + 2*4+5 + 12);
|
||||||
BYTE *const plte = (BYTE *)gama + 4 + 12;
|
BYTE *const plte = (BYTE *)gama + 4 + 12;
|
||||||
|
size_t work_len;
|
||||||
|
|
||||||
sig[0] = MAKE_ID(137,'P','N','G');
|
sig[0] = MAKE_ID(137,'P','N','G');
|
||||||
sig[1] = MAKE_ID(13,10,26,10);
|
sig[1] = MAKE_ID(13,10,26,10);
|
||||||
|
|
||||||
ihdr->Width = BigLong (canvas->GetWidth ());
|
ihdr->Width = BigLong(width);
|
||||||
ihdr->Height = BigLong (canvas->GetHeight ());
|
ihdr->Height = BigLong(height);
|
||||||
ihdr->BitDepth = 8;
|
ihdr->BitDepth = 8;
|
||||||
ihdr->ColorType = 3;
|
ihdr->ColorType = color_type == SS_PAL ? 3 : 2;
|
||||||
ihdr->Compression = 0;
|
ihdr->Compression = 0;
|
||||||
ihdr->Filter = 0;
|
ihdr->Filter = 0;
|
||||||
ihdr->Interlace = 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)));
|
*gama = BigLong (int (45454.5f * (png_gamma == 0.f ? Gamma : png_gamma)));
|
||||||
MakeChunk (gama, MAKE_ID('g','A','M','A'), 4);
|
MakeChunk (gama, MAKE_ID('g','A','M','A'), 4);
|
||||||
|
|
||||||
StuffPalette (palette, plte);
|
if (color_type == SS_PAL)
|
||||||
MakeChunk (plte, MAKE_ID('P','L','T','E'), 256*3);
|
{
|
||||||
|
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 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)
|
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.
|
// Given a bitmap, creates one or more IDAT chunks in the given file.
|
||||||
// Returns true on success.
|
// Returns true on success.
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
static bool StuffBitmap (const DCanvas *canvas, FILE *file)
|
bool M_SaveBitmap(const BYTE *from, ESSType color_type, int width, int height, int pitch, 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)
|
|
||||||
{
|
{
|
||||||
|
Byte prior[MAXWIDTH];
|
||||||
Byte buffer[PNG_WRITE_SIZE];
|
Byte buffer[PNG_WRITE_SIZE];
|
||||||
Byte zero = 0;
|
Byte temprow[5][1 + MAXWIDTH*3];
|
||||||
z_stream stream;
|
z_stream stream;
|
||||||
int err;
|
int err;
|
||||||
int y;
|
int y;
|
||||||
|
@ -761,43 +916,74 @@ bool M_SaveBitmap(BYTE * from, int width, int height, int pitch, FILE *file)
|
||||||
stream.next_out = buffer;
|
stream.next_out = buffer;
|
||||||
stream.avail_out = sizeof(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--;
|
memset(prior, 0, width * 3);
|
||||||
for (int i = 2; i && err == Z_OK; --i)
|
}
|
||||||
|
|
||||||
|
while (y-- > 0 && err == Z_OK)
|
||||||
|
{
|
||||||
|
switch (color_type)
|
||||||
{
|
{
|
||||||
const int flushiness = (y == 0 && i == 1) ? Z_FINISH : 0;
|
case SS_PAL:
|
||||||
if (i == 2)
|
memcpy(&temprow[0][1], from, width);
|
||||||
{ // always use filter type 0
|
// always use filter type 0 for paletted images
|
||||||
stream.next_in = &zero;
|
stream.next_in = temprow[0];
|
||||||
stream.avail_in = 1;
|
stream.avail_in = width + 1;
|
||||||
}
|
break;
|
||||||
else
|
|
||||||
|
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;
|
temprow[0][x*3 + 1] = from[x*4 + 2];
|
||||||
stream.avail_in = width;
|
temprow[0][x*3 + 2] = from[x*4 + 1];
|
||||||
from += pitch;
|
temprow[0][x*3 + 3] = from[x*4];
|
||||||
}
|
}
|
||||||
err = deflate (&stream, flushiness);
|
stream.next_in = temprow[SelectFilter(temprow, prior, width)];
|
||||||
if (err != Z_OK)
|
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;
|
break;
|
||||||
}
|
|
||||||
stream.next_out = buffer;
|
|
||||||
stream.avail_out = sizeof(buffer);
|
|
||||||
if (stream.avail_in != 0)
|
|
||||||
{
|
|
||||||
err = deflate (&stream, flushiness);
|
|
||||||
if (err != Z_OK)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,8 @@
|
||||||
// The passed file should be a newly created file.
|
// The passed file should be a newly created file.
|
||||||
// This function writes the PNG signature and the IHDR, gAMA, PLTE, and IDAT
|
// This function writes the PNG signature and the IHDR, gAMA, PLTE, and IDAT
|
||||||
// chunks.
|
// 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.
|
// Creates a grayscale 1x1 PNG file. Used for savegames without savepics.
|
||||||
bool M_CreateDummyPNG (FILE *file);
|
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.
|
// Appends the IEND chunk to a PNG file.
|
||||||
bool M_FinishPNG (FILE *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 --------------------------------------------------------------
|
// 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 *DCanvas::CanvasChain = NULL;
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// DCanvas Constructor
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
DCanvas::DCanvas (int _width, int _height)
|
DCanvas::DCanvas (int _width, int _height)
|
||||||
{
|
{
|
||||||
// Init member vars
|
// Init member vars
|
||||||
|
@ -198,6 +204,12 @@ DCanvas::DCanvas (int _width, int _height)
|
||||||
CanvasChain = this;
|
CanvasChain = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// DCanvas Destructor
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
DCanvas::~DCanvas ()
|
DCanvas::~DCanvas ()
|
||||||
{
|
{
|
||||||
// Remove from list of active canvases
|
// Remove from list of active canvases
|
||||||
|
@ -218,6 +230,12 @@ DCanvas::~DCanvas ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// DCanvas :: IsValid
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
bool DCanvas::IsValid ()
|
bool DCanvas::IsValid ()
|
||||||
{
|
{
|
||||||
// A nun-subclassed DCanvas is never valid
|
// 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)
|
void DCanvas::Clear (int left, int top, int right, int bottom, int palcolor, uint32 color)
|
||||||
{
|
{
|
||||||
int x, y;
|
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)
|
void DCanvas::Dim (PalEntry color)
|
||||||
{
|
{
|
||||||
PalEntry dimmer;
|
PalEntry dimmer;
|
||||||
|
@ -320,6 +353,14 @@ void DCanvas::Dim (PalEntry color)
|
||||||
Dim (dimmer, amount, 0, 0, Width, Height);
|
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)
|
void DCanvas::Dim (PalEntry color, float damount, int x1, int y1, int w, int h)
|
||||||
{
|
{
|
||||||
if (damount == 0.f)
|
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
|
bool DCanvas::UsesColormap() const
|
||||||
{
|
{
|
||||||
return true;
|
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 V_GetColorFromString (const DWORD *palette, const char *cstr)
|
||||||
{
|
{
|
||||||
int c[3], i, p;
|
int c[3], i, p;
|
||||||
|
@ -434,11 +523,20 @@ int V_GetColorFromString (const DWORD *palette, const char *cstr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (palette)
|
if (palette)
|
||||||
return ColorMatcher.Pick (c[0]>>8, c[1]>>8, c[2]>>8);
|
return ColorMatcher.Pick (c[0], c[1], c[2]);
|
||||||
else
|
else
|
||||||
return MAKERGB(c[0], c[1], c[2]);
|
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)
|
FString V_GetColorStringByName (const char *name)
|
||||||
{
|
{
|
||||||
FMemLump rgbNames;
|
FMemLump rgbNames;
|
||||||
|
@ -520,6 +618,14 @@ FString V_GetColorStringByName (const char *name)
|
||||||
return FString();
|
return FString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// V_GetColor
|
||||||
|
//
|
||||||
|
// Works like V_GetColorFromString(), but also understands X11 color names.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
int V_GetColor (const DWORD *palette, const char *str)
|
int V_GetColor (const DWORD *palette, const char *str)
|
||||||
{
|
{
|
||||||
FString string = V_GetColorStringByName (str);
|
FString string = V_GetColorStringByName (str);
|
||||||
|
@ -536,7 +642,14 @@ int V_GetColor (const DWORD *palette, const char *str)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// BuildTransTable
|
||||||
|
//
|
||||||
// Build the tables necessary for blending
|
// Build the tables necessary for blending
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
static void BuildTransTable (const PalEntry *palette)
|
static void BuildTransTable (const PalEntry *palette)
|
||||||
{
|
{
|
||||||
int r, g, b;
|
int r, g, b;
|
||||||
|
@ -570,6 +683,12 @@ static void BuildTransTable (const PalEntry *palette)
|
||||||
Col2RGB8_LessPrecision[64] = Col2RGB8[64];
|
Col2RGB8_LessPrecision[64] = Col2RGB8[64];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// DCanvas :: CalcGamma
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
void DCanvas::CalcGamma (float gamma, BYTE gammalookup[256])
|
void DCanvas::CalcGamma (float gamma, BYTE gammalookup[256])
|
||||||
{
|
{
|
||||||
// I found this formula on the web at
|
// 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)
|
DSimpleCanvas::DSimpleCanvas (int width, int height)
|
||||||
: DCanvas (width, height)
|
: DCanvas (width, height)
|
||||||
{
|
{
|
||||||
|
@ -627,6 +754,12 @@ DSimpleCanvas::DSimpleCanvas (int width, int height)
|
||||||
memset (MemBuffer, 0, Pitch * height);
|
memset (MemBuffer, 0, Pitch * height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// DSimpleCanvas Destructor
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
DSimpleCanvas::~DSimpleCanvas ()
|
DSimpleCanvas::~DSimpleCanvas ()
|
||||||
{
|
{
|
||||||
if (MemBuffer != NULL)
|
if (MemBuffer != NULL)
|
||||||
|
@ -636,11 +769,23 @@ DSimpleCanvas::~DSimpleCanvas ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// DSimpleCanvas :: IsValid
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
bool DSimpleCanvas::IsValid ()
|
bool DSimpleCanvas::IsValid ()
|
||||||
{
|
{
|
||||||
return (MemBuffer != NULL);
|
return (MemBuffer != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// DSimpleCanvas :: Lock
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
bool DSimpleCanvas::Lock ()
|
bool DSimpleCanvas::Lock ()
|
||||||
{
|
{
|
||||||
if (LockCount == 0)
|
if (LockCount == 0)
|
||||||
|
@ -651,6 +796,12 @@ bool DSimpleCanvas::Lock ()
|
||||||
return false; // System surfaces are never lost
|
return false; // System surfaces are never lost
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// DSimpleCanvas :: Unlock
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
void DSimpleCanvas::Unlock ()
|
void DSimpleCanvas::Unlock ()
|
||||||
{
|
{
|
||||||
if (--LockCount <= 0)
|
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)
|
DFrameBuffer::DFrameBuffer (int width, int height)
|
||||||
: DSimpleCanvas (width, height)
|
: DSimpleCanvas (width, height)
|
||||||
{
|
{
|
||||||
|
@ -667,6 +827,14 @@ DFrameBuffer::DFrameBuffer (int width, int height)
|
||||||
Accel2D = false;
|
Accel2D = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// DFrameBuffer :: DrawRateStuff
|
||||||
|
//
|
||||||
|
// Draws the fps counter, dot ticker, and palette debug.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
void DFrameBuffer::DrawRateStuff ()
|
void DFrameBuffer::DrawRateStuff ()
|
||||||
{
|
{
|
||||||
// Draws frame time and cumulative fps
|
// 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()
|
FPaletteTester::FPaletteTester()
|
||||||
{
|
{
|
||||||
Width = 16;
|
Width = 16;
|
||||||
|
@ -754,11 +930,23 @@ FPaletteTester::FPaletteTester()
|
||||||
MakeTexture();
|
MakeTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FPaletteTester :: CheckModified
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
bool FPaletteTester::CheckModified()
|
bool FPaletteTester::CheckModified()
|
||||||
{
|
{
|
||||||
return CurTranslation != WantTranslation;
|
return CurTranslation != WantTranslation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FPaletteTester :: SetTranslation
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
void FPaletteTester::SetTranslation(int num)
|
void FPaletteTester::SetTranslation(int num)
|
||||||
{
|
{
|
||||||
if (num >= 1 && num <= 9)
|
if (num >= 1 && num <= 9)
|
||||||
|
@ -767,10 +955,22 @@ void FPaletteTester::SetTranslation(int num)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FPaletteTester :: Unload
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
void FPaletteTester::Unload()
|
void FPaletteTester::Unload()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FPaletteTester :: GetColumn
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
const BYTE *FPaletteTester::GetColumn (unsigned int column, const Span **spans_out)
|
const BYTE *FPaletteTester::GetColumn (unsigned int column, const Span **spans_out)
|
||||||
{
|
{
|
||||||
if (CurTranslation != WantTranslation)
|
if (CurTranslation != WantTranslation)
|
||||||
|
@ -785,6 +985,12 @@ const BYTE *FPaletteTester::GetColumn (unsigned int column, const Span **spans_o
|
||||||
return Pixels + column*16;
|
return Pixels + column*16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FPaletteTester :: GetPixels
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
const BYTE *FPaletteTester::GetPixels ()
|
const BYTE *FPaletteTester::GetPixels ()
|
||||||
{
|
{
|
||||||
if (CurTranslation != WantTranslation)
|
if (CurTranslation != WantTranslation)
|
||||||
|
@ -794,6 +1000,12 @@ const BYTE *FPaletteTester::GetPixels ()
|
||||||
return Pixels;
|
return Pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FPaletteTester :: MakeTexture
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
void FPaletteTester::MakeTexture()
|
void FPaletteTester::MakeTexture()
|
||||||
{
|
{
|
||||||
int i, j, k, t;
|
int i, j, k, t;
|
||||||
|
@ -814,6 +1026,15 @@ void FPaletteTester::MakeTexture()
|
||||||
CurTranslation = t;
|
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)
|
void DFrameBuffer::CopyFromBuff (BYTE *src, int srcPitch, int width, int height, BYTE *dest)
|
||||||
{
|
{
|
||||||
if (Pitch == width && Pitch == Width && srcPitch == width)
|
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)
|
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)
|
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)
|
bool DFrameBuffer::Begin2D (bool copy3d)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// DFrameBuffer :: CreateTexture
|
||||||
|
//
|
||||||
|
// Creates a native texture for a game texture, if supported.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
FNativeTexture *DFrameBuffer::CreateTexture(FTexture *gametex, bool wrapping)
|
FNativeTexture *DFrameBuffer::CreateTexture(FTexture *gametex, bool wrapping)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// DFrameBuffer :: CreatePalette
|
||||||
|
//
|
||||||
|
// Creates a native palette from a remap table, if supported.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
FNativePalette *DFrameBuffer::CreatePalette(FRemapTable *remap)
|
FNativePalette *DFrameBuffer::CreatePalette(FRemapTable *remap)
|
||||||
{
|
{
|
||||||
return NULL;
|
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)
|
bool DFrameBuffer::WipeStartScreen(int type)
|
||||||
{
|
{
|
||||||
return wipe_StartScreen(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()
|
void DFrameBuffer::WipeEndScreen()
|
||||||
{
|
{
|
||||||
wipe_EndScreen();
|
wipe_EndScreen();
|
||||||
Unlock();
|
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)
|
bool DFrameBuffer::WipeDo(int ticks)
|
||||||
{
|
{
|
||||||
Lock(true);
|
Lock(true);
|
||||||
return wipe_ScreenWipe(ticks);
|
return wipe_ScreenWipe(ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// DFrameBuffer :: WipeCleanup
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
void DFrameBuffer::WipeCleanup()
|
void DFrameBuffer::WipeCleanup()
|
||||||
{
|
{
|
||||||
wipe_Cleanup();
|
wipe_Cleanup();
|
||||||
|
|
|
@ -117,13 +117,18 @@ enum
|
||||||
HUD_HorizCenter
|
HUD_HorizCenter
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Screenshot buffer image data types
|
||||||
|
enum ESSType
|
||||||
|
{
|
||||||
|
SS_PAL,
|
||||||
|
SS_RGB,
|
||||||
|
SS_BGRA
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// VIDEO
|
// VIDEO
|
||||||
//
|
//
|
||||||
// [RH] Made screens more implementation-independant:
|
// [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
|
class DCanvas : public DObject
|
||||||
{
|
{
|
||||||
|
@ -178,11 +183,13 @@ public:
|
||||||
// Can be overridden so that the colormaps for sector color/fade won't be built.
|
// Can be overridden so that the colormaps for sector color/fade won't be built.
|
||||||
virtual bool UsesColormap() const;
|
virtual bool UsesColormap() const;
|
||||||
|
|
||||||
// software renderer always returns true but other renderers may not want to implement PCX.
|
// Retrieves a buffer containing image data for a screenshot.
|
||||||
bool CanWritePCX();
|
// 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
|
// Releases the screenshot buffer.
|
||||||
void Save(const char *filename, bool writepcx);
|
virtual void ReleaseScreenshotBuffer();
|
||||||
|
|
||||||
// Text drawing functions -----------------------------------------------
|
// Text drawing functions -----------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -227,6 +227,8 @@ D3DFB::D3DFB (int width, int height, bool fullscreen)
|
||||||
FBTexture = NULL;
|
FBTexture = NULL;
|
||||||
TempRenderTexture = NULL;
|
TempRenderTexture = NULL;
|
||||||
InitialWipeScreen = NULL;
|
InitialWipeScreen = NULL;
|
||||||
|
ScreenshotTexture = NULL;
|
||||||
|
ScreenshotSurface = NULL;
|
||||||
FinalWipeScreen = NULL;
|
FinalWipeScreen = NULL;
|
||||||
PaletteTexture = NULL;
|
PaletteTexture = NULL;
|
||||||
StencilPaletteTexture = NULL;
|
StencilPaletteTexture = NULL;
|
||||||
|
@ -439,6 +441,8 @@ void D3DFB::ReleaseResources ()
|
||||||
KillNativeTexs();
|
KillNativeTexs();
|
||||||
KillNativePals();
|
KillNativePals();
|
||||||
ReleaseDefaultPoolItems();
|
ReleaseDefaultPoolItems();
|
||||||
|
SAFE_RELEASE( ScreenshotSurface );
|
||||||
|
SAFE_RELEASE( ScreenshotTexture );
|
||||||
SAFE_RELEASE( PaletteTexture );
|
SAFE_RELEASE( PaletteTexture );
|
||||||
SAFE_RELEASE( StencilPaletteTexture );
|
SAFE_RELEASE( StencilPaletteTexture );
|
||||||
SAFE_RELEASE( ShadedPaletteTexture );
|
SAFE_RELEASE( ShadedPaletteTexture );
|
||||||
|
@ -1087,6 +1091,161 @@ void D3DFB::SetBlendingRect(int x1, int y1, int x2, int y2)
|
||||||
BlendingRect.bottom = 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 */
|
/* 2D Stuff */
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
|
@ -1435,40 +1594,43 @@ void D3DFB::PackingTexture::AllocateImage(D3DFB::PackedTexture *box, int w, int
|
||||||
box->Prev = &UsedList;
|
box->Prev = &UsedList;
|
||||||
|
|
||||||
// If we didn't use the whole box, split the remainder into the empty list.
|
// If we didn't use the whole box, split the remainder into the empty list.
|
||||||
#if 1
|
|
||||||
// Split like this:
|
if (box->Area.bottom + 7 < start.bottom && box->Area.right + 7 < start.right)
|
||||||
// +---+------+
|
|
||||||
// |###| |
|
|
||||||
// +---+------+
|
|
||||||
// | |
|
|
||||||
// | |
|
|
||||||
// +----------+
|
|
||||||
// Empirical evidence indicates that this gives the best utilization.
|
|
||||||
if (box->Area.bottom < start.bottom)
|
|
||||||
{
|
{
|
||||||
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)
|
bool D3DFB::WipeStartScreen(int type)
|
||||||
{
|
{
|
||||||
IDirect3DSurface9 *surf, *tsurf;
|
IDirect3DSurface9 *tsurf;
|
||||||
D3DSURFACE_DESC desc;
|
D3DSURFACE_DESC desc;
|
||||||
|
|
||||||
if (!test2d)
|
if (!test2d)
|
||||||
|
@ -161,106 +161,39 @@ bool D3DFB::WipeStartScreen(int type)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Windowed)
|
InitialWipeScreen = GetCurrentScreen();
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (!Windowed)
|
||||||
{
|
{
|
||||||
if (FAILED(D3DDevice->GetFrontBufferData(0, surf)))
|
|
||||||
{
|
|
||||||
surf->Release();
|
|
||||||
InitialWipeScreen->Release();
|
|
||||||
InitialWipeScreen = NULL;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
FinalWipeScreen = TempRenderTexture;
|
FinalWipeScreen = TempRenderTexture;
|
||||||
}
|
}
|
||||||
else
|
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
|
// Create another texture to copy the final wipe screen to so
|
||||||
// we can still gamma correct the wipe. Since this is just for
|
// we can still gamma correct the wipe. Since this is just for
|
||||||
// gamma correction, it's okay to fail (though not desirable.)
|
// gamma correction, it's okay to fail (though not desirable.)
|
||||||
if (GammaFixerShader != NULL && Gamma != 1)
|
if (GammaFixerShader != NULL && Gamma != 1)
|
||||||
{
|
{
|
||||||
if (FAILED(tsurf->GetDesc(&desc)) ||
|
if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &tsurf)))
|
||||||
FAILED(D3DDevice->CreateTexture(desc.Width, desc.Height,
|
|
||||||
1, D3DUSAGE_RENDERTARGET, desc.Format, D3DPOOL_DEFAULT,
|
|
||||||
&FinalWipeScreen, NULL)))
|
|
||||||
{
|
{
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
FinalWipeScreen = TempRenderTexture;
|
FinalWipeScreen = TempRenderTexture;
|
||||||
}
|
}
|
||||||
tsurf->Release();
|
|
||||||
}
|
}
|
||||||
surf->Release();
|
|
||||||
// Even fullscreen will render to the TempRenderTexture, so we can have
|
// Make even fullscreen model render to the TempRenderTexture, so
|
||||||
// a copy of the new screen readily available.
|
// we can have a copy of the new screen readily available.
|
||||||
GatheringWipeScreen = true;
|
GatheringWipeScreen = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -237,6 +237,8 @@ public:
|
||||||
void Blank ();
|
void Blank ();
|
||||||
bool PaintToWindow ();
|
bool PaintToWindow ();
|
||||||
void SetVSync (bool vsync);
|
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);
|
void SetBlendingRect (int x1, int y1, int x2, int y2);
|
||||||
bool Begin2D (bool copy3d);
|
bool Begin2D (bool copy3d);
|
||||||
FNativeTexture *CreateTexture (FTexture *gametex, bool wrapping);
|
FNativeTexture *CreateTexture (FTexture *gametex, bool wrapping);
|
||||||
|
@ -297,6 +299,7 @@ private:
|
||||||
void FillPresentParameters (D3DPRESENT_PARAMETERS *pp, bool fullscreen, bool vsync);
|
void FillPresentParameters (D3DPRESENT_PARAMETERS *pp, bool fullscreen, bool vsync);
|
||||||
void CalcFullscreenCoords (FBVERTEX verts[4], bool viewarea_only, D3DCOLOR color0, D3DCOLOR color1) const;
|
void CalcFullscreenCoords (FBVERTEX verts[4], bool viewarea_only, D3DCOLOR color0, D3DCOLOR color1) const;
|
||||||
bool Reset();
|
bool Reset();
|
||||||
|
IDirect3DTexture9 *GetCurrentScreen();
|
||||||
void ReleaseDefaultPoolItems();
|
void ReleaseDefaultPoolItems();
|
||||||
void KillNativePals();
|
void KillNativePals();
|
||||||
void KillNativeTexs();
|
void KillNativeTexs();
|
||||||
|
@ -360,6 +363,8 @@ private:
|
||||||
IDirect3DTexture9 *PaletteTexture;
|
IDirect3DTexture9 *PaletteTexture;
|
||||||
IDirect3DTexture9 *StencilPaletteTexture;
|
IDirect3DTexture9 *StencilPaletteTexture;
|
||||||
IDirect3DTexture9 *ShadedPaletteTexture;
|
IDirect3DTexture9 *ShadedPaletteTexture;
|
||||||
|
IDirect3DTexture9 *ScreenshotTexture;
|
||||||
|
IDirect3DSurface9 *ScreenshotSurface;
|
||||||
|
|
||||||
IDirect3DVertexBuffer9 *VertexBuffer;
|
IDirect3DVertexBuffer9 *VertexBuffer;
|
||||||
FBVERTEX *VertexData;
|
FBVERTEX *VertexData;
|
||||||
|
|
Loading…
Reference in New Issue