/*
===========================================================================
ARX FATALIS GPL Source Code
Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company.
This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code').
Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code. If not, see
.
In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these
additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx
Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o
ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//////////////////////////////////////////////////////////////////////////////////////
// @@ @@@ @@@ @@ @@@@@ //
// @@@ @@@@@@ @@@ @@ @@@@ @@@ @@@ //
// @@@ @@@@@@@ @@@ @@@@ @@@@ @@ @@@@ //
// @@@ @@ @@@@ @@@ @@@@@ @@@@@@ @@@ @@@ //
// @@@@@ @@ @@@@ @@@ @@@@@ @@@@@@@ @@@ @ @@@ //
// @@@@@ @@ @@@@ @@@@@@@@ @@@@ @@@ @@@@@ @@ @@@@@@@ //
// @@ @@@ @@ @@@@ @@@@@@@ @@@ @@@ @@@@@@ @@ @@@@ //
// @@@ @@@ @@@ @@@@ @@@@@ @@@@@@@@@ @@@@@@@ @@@ @@@@ //
// @@@ @@@@ @@@@@@@ @@@@@@ @@@ @@@@ @@@ @@@ @@@ @@@@ //
// @@@@@@@@ @@@@@ @@@@@@@@@@ @@@ @@@ @@@ @@@ @@@ @@@@@ //
// @@@ @@@@ @@@@ @@@ @@@@@@@ @@@ @@@ @@@@ @@@ @@@@ @@@@@ //
//@@@ @@@@ @@@@@ @@@ @@@@@@ @@ @@@ @@@@ @@@@@@@ @@@@@ @@@@@ //
//@@@ @@@@@ @@@@@ @@@@ @@@ @@ @@ @@@@ @@@@@@@ @@@@@@@@@ //
//@@@ @@@@ @@@@@@@ @@@@ @@ @@ @@@@ @@@@@ @@@@@ //
//@@@ @@@@ @@@@@@@ @@@@ @@ @@ @@@@ @@@@@ @@ //
//@@@ @@@ @@@ @@@@@ @@ @@@ //
// @@@ @@@ @@ @@ STUDIOS //
//////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
// ARX_Snapshot
//////////////////////////////////////////////////////////////////////////////////////
//
// Description:
// ARX Snapshot management
//
// Updates: (date) (person) (update)
//
// Code: Cyril Meynier
//
// Copyright (c) 1999-2000 ARKANE Studios SA. All rights reserved
//////////////////////////////////////////////////////////////////////////////////////
#include
#include
#include "ARX_SnapShot.h"
#define _CRTDBG_MAP_ALLOC
#include
SnapShot * pSnapShot;
SNAPSHOTINFO snapshotdata;
long CURRENTSNAPNUM = 0;
struct TargaHeader
{
BYTE IDLength;
BYTE ColormapType;
BYTE ImageType;
BYTE ColormapSpecification[5];
WORD XOrigin;
WORD YOrigin;
WORD ImageWidth;
WORD ImageHeight;
BYTE PixelDepth;
BYTE ImageDescriptor;
} tga;
typedef struct
{
char name[256];
unsigned char buffer[640*480*2];
} MEMORYSNAP;
MEMORYSNAP * snaps = NULL;
long MAXSNAPS = 0;
long InitMemorySnaps()
{
if (snaps) free(snaps);
snaps = NULL;
long number = 1600;
long cool = 1;
while ((cool) && (number))
{
cool = 0;
if (snaps) free(snaps);
snaps = (MEMORYSNAP *)malloc(sizeof(MEMORYSNAP) * number);
if (snaps == NULL) cool = 1;
number -= 4;
}
number -= 8;
if (snaps) free(snaps);
snaps = NULL;
if (number > 0)
snaps = (MEMORYSNAP *)malloc(sizeof(MEMORYSNAP) * number);
MAXSNAPS = number;
return number;
}
void FlushMemorySnaps(long flag)
{
if (flag == 0)
{
if (snaps) free(snaps);
snaps = NULL;
MAXSNAPS = 0;
return;
}
static char buff[640*2];
long targetsizeX = snapshotdata.xsize;
long targetsizeY = snapshotdata.ysize;
float xratio = 640.f / (float)targetsizeX;
float yratio = 480.f / (float)targetsizeY;
tga.IDLength = sizeof(TargaHeader);
tga.ColormapType = 0;
tga.ColormapSpecification[0] = 0;
tga.ColormapSpecification[1] = 0;
tga.ColormapSpecification[2] = 0;
tga.ColormapSpecification[3] = 0;
tga.ColormapSpecification[4] = 0;
tga.XOrigin = 0;
tga.YOrigin = 0;
tga.ImageType = 0x02;
tga.ImageWidth = (unsigned short)targetsizeX;
tga.ImageHeight = (unsigned short)targetsizeY;
tga.PixelDepth = 16;
tga.ImageDescriptor = 32;
danaeApp.Lock();
DWORD dwRMask = danaeApp.ddsd.ddpfPixelFormat.dwRBitMask;
DWORD dwGMask = danaeApp.ddsd.ddpfPixelFormat.dwGBitMask;
DWORD dwBMask = danaeApp.ddsd.ddpfPixelFormat.dwBBitMask;
DWORD dwAMask = danaeApp.ddsd.ddpfPixelFormat.dwRGBAlphaBitMask;
long pitch = danaeApp.ddsd.lPitch ;
danaeApp.Unlock();
pitch = 640;
DWORD dwRShiftL = 8, dwRShiftR = 0;
DWORD dwGShiftL = 8, dwGShiftR = 0;
DWORD dwBShiftL = 8, dwBShiftR = 0;
DWORD dwAShiftL = 8, dwAShiftR = 0;
DWORD dwMask;
for (dwMask = dwRMask; dwMask && !(dwMask & 0x1); dwMask >>= 1) dwRShiftR++;
for (; dwMask; dwMask >>= 1) dwRShiftL--;
for (dwMask = dwGMask; dwMask && !(dwMask & 0x1); dwMask >>= 1) dwGShiftR++;
for (; dwMask; dwMask >>= 1) dwGShiftL--;
for (dwMask = dwBMask; dwMask && !(dwMask & 0x1); dwMask >>= 1) dwBShiftR++;
for (; dwMask; dwMask >>= 1) dwBShiftL--;
for (dwMask = dwAMask; dwMask && !(dwMask & 0x1); dwMask >>= 1) dwAShiftR++;
for (; dwMask; dwMask >>= 1) dwAShiftL--;
for (long i = 0; i < CURRENTSNAPNUM; i++)
{
FILE * file;
file = fopen(snaps[i].name, "wb");
if (NULL == file)
{
return;
}
fwrite(&tga, sizeof(TargaHeader), 1, file);
long n;
unsigned short col;
unsigned char * v = (unsigned char *)snaps[i].buffer;
fwrite(&tga, 1, 20, file);
DWORD dwOffset;
DWORD x;
for (long yy = 1; yy <= targetsizeY; yy++)
{
dwOffset = (long)((float)yy * yratio) * pitch; //640;
long pos = 0;
for (long xx = 0; xx < targetsizeX; xx++)
{
x = (long)((float)xx * xratio);
n = (dwOffset + x + 1) << 1;
memcpy(&col, v + n, 2);
unsigned short r, g, b;
b = (unsigned short)((col & dwBMask) >> dwBShiftR) << dwBShiftL;
g = (unsigned short)((col & dwGMask) >> dwGShiftR) << dwGShiftL;
r = (unsigned short)((col & dwRMask) >> dwRShiftR) << dwRShiftL;
col = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
memcpy(buff + pos, &col, 2);
pos += 2;
}
fwrite(buff, pos, 1, file);
}
fclose(file);
}
if (snaps) free(snaps);
snaps = NULL;
MAXSNAPS = 0;
}
//-----------------------------------------------------------------------------
SnapShot::SnapShot(char * _pDir, char * _pName, bool _bReplace)
{
ulNum = 0;
if (_pName)
{
char tTxt[256];
if (_pDir)
{
strcpy(tTxt, _pDir);
}
else
{
*tTxt = 0;
}
strcat(tTxt, _pName);
pName = strdup(tTxt);
strupr(pName);
strcpy(tTxt, Project.workingdir);
if (_pDir)
{
strcpy(tTxt, _pDir);
}
strcat(tTxt, "*.bmp");
if (!_bReplace)
{
char tTemp[sizeof(WIN32_FIND_DATA)+2];
WIN32_FIND_DATA * w32fdata = (WIN32_FIND_DATA *)tTemp;
HANDLE h = FindFirstFile((const char *)tTxt, w32fdata);
if (h == INVALID_HANDLE_VALUE) return;
do
{
if (!(w32fdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
strcpy(tTxt, w32fdata->cFileName);
strupr(tTxt);
if (strstr(tTxt, pName)) ulNum++;
}
}
while (FindNextFile(h, w32fdata));
FindClose(h);
}
}
else
{
pName = NULL;
}
}
//-----------------------------------------------------------------------------
SnapShot::~SnapShot()
{
if (pName)
{
free((void *)pName);
pName = NULL;
}
}
//-----------------------------------------------------------------------------
//Sauvegarde en BMP 32bits
bool SnapShot::GetSnapShot()
{
DDSURFACEDESC2 ddsd2;
memset((void *)&ddsd2, 0, sizeof(ddsd2));
ddsd2.dwSize = sizeof(ddsd2);
if (danaeApp.m_pFramework->m_pddsBackBuffer->Lock(NULL, &ddsd2, DDLOCK_SURFACEMEMORYPTR, 0) != DD_OK)
{
return false;
}
unsigned long * pulMemorySnapShot = new unsigned long[ddsd2.dwWidth*ddsd2.dwHeight];
if (!pulMemorySnapShot)
{
danaeApp.m_pFramework->m_pddsBackBuffer->Unlock(NULL);
return false;
}
unsigned long * pulMemorySnapShotClone = pulMemorySnapShot;
unsigned char * pMemoryBase = (unsigned char *)ddsd2.lpSurface;
int iPitch = ddsd2.lPitch * (ddsd2.dwHeight - 1);
switch (ddsd2.ddpfPixelFormat.dwRGBBitCount)
{
case 16:
{
int iDecalR = 0;
int iDecalG = 0;
int iDecalB = 0;
int iDec;
iDec = ddsd2.ddpfPixelFormat.dwRBitMask;
while (!(iDec & 0x800000))
{
iDecalR++;
iDec <<= 1;
}
iDec = ddsd2.ddpfPixelFormat.dwGBitMask;
while (!(iDec & 0x8000))
{
iDec <<= 1;
iDecalG++;
}
iDec = ddsd2.ddpfPixelFormat.dwBBitMask;
while (!(iDec & 0x80))
{
iDec <<= 1;
iDecalB++;
}
for (unsigned int iY = 0; iY < ddsd2.dwHeight; iY++)
{
unsigned short * pMemory = (unsigned short *)(pMemoryBase + iPitch);
for (unsigned int iX = 0; iX < ddsd2.dwWidth; iX++)
{
int iR = (pMemory[iX] & ddsd2.ddpfPixelFormat.dwRBitMask) << iDecalR;
int iG = (pMemory[iX] & ddsd2.ddpfPixelFormat.dwGBitMask) << iDecalG;
int iB = (pMemory[iX] & ddsd2.ddpfPixelFormat.dwBBitMask) << iDecalB;
*pulMemorySnapShotClone++ = iR | iG | iB;
}
iPitch -= ddsd2.lPitch;
}
}
break;
case 24:
{
for (unsigned int iY = 0; iY < ddsd2.dwHeight; iY++)
{
unsigned char * pMemory = (unsigned char *)(pMemoryBase + iPitch);
for (unsigned int iX = 0; iX < ddsd2.dwWidth; iX++)
{
int iR = *pMemory++;
int iG = *pMemory++;
int iB = *pMemory++;
*pulMemorySnapShotClone++ = (iR << 16) | (iG << 8) | iB;
}
iPitch -= ddsd2.lPitch;
}
}
break;
case 32:
{
for (unsigned int iY = 0; iY < ddsd2.dwHeight; iY++)
{
unsigned long * pMemory = (unsigned long *)(pMemoryBase + iPitch);
memcpy(pulMemorySnapShotClone, pMemory, ddsd2.dwWidth << 2);
pulMemorySnapShotClone += ddsd2.dwWidth;
iPitch -= ddsd2.lPitch;
}
}
break;
}
danaeApp.m_pFramework->m_pddsBackBuffer->Unlock(NULL);
//sauvegarde bmp
char tTxt[256];
sprintf(tTxt, "%s%s_%d.bmp", Project.workingdir, pName, ulNum);
FILE * fFile = fopen(tTxt, "wb");
if (!fFile)
{
delete pulMemorySnapShot;
return false;
}
ulNum++;
BITMAPFILEHEADER bfhBitmapFileHeader;
bfhBitmapFileHeader.bfType = ('M' << 8) | ('B');
bfhBitmapFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + ((ddsd2.dwWidth * ddsd2.dwHeight) << 2);
bfhBitmapFileHeader.bfReserved1 = bfhBitmapFileHeader.bfReserved2 = 0;
bfhBitmapFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
fwrite(&bfhBitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, fFile);
BITMAPINFOHEADER bihBitmapInfoHeader;
bihBitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bihBitmapInfoHeader.biWidth = ddsd2.dwWidth;
bihBitmapInfoHeader.biHeight = ddsd2.dwHeight;
bihBitmapInfoHeader.biPlanes = 1;
bihBitmapInfoHeader.biBitCount = 32;
bihBitmapInfoHeader.biCompression = BI_RGB;
bihBitmapInfoHeader.biSizeImage = 0;
bihBitmapInfoHeader.biXPelsPerMeter = 0;
bihBitmapInfoHeader.biYPelsPerMeter = 0;
bihBitmapInfoHeader.biClrUsed = 0;
bihBitmapInfoHeader.biClrImportant = 0;
fwrite(&bihBitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, fFile);
fwrite(pulMemorySnapShot, (ddsd2.dwWidth * ddsd2.dwHeight) << 2, 1, fFile);
fclose(fFile);
delete pulMemorySnapShot;
return true;
}
//-----------------------------------------------------------------------------
//Sauvegarde en BMP 24bits
bool SnapShot::GetSnapShotDim(int _iWith, int _iHeight)
{
DDSURFACEDESC2 ddsd2;
memset((void *)&ddsd2, 0, sizeof(ddsd2));
ddsd2.dwSize = sizeof(ddsd2);
danaeApp.m_pFramework->m_pddsBackBuffer->GetSurfaceDesc(&ddsd2);
LPDIRECTDRAW7 pDD;
LPDIRECTDRAWSURFACE7 pddsRender;
GDevice->GetRenderTarget(&pddsRender);
pddsRender->GetDDInterface((VOID **)&pDD);
pddsRender->Release();
LPDIRECTDRAWSURFACE7 m_pddsSurface = NULL;
ddsd2.dwSize = sizeof(ddsd2);
ddsd2.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
ddsd2.dwWidth = _iWith;
ddsd2.dwHeight = _iHeight;
ddsd2.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
pDD->CreateSurface(&ddsd2, &m_pddsSurface, NULL);
pDD->Release();
m_pddsSurface->Blt(NULL, danaeApp.m_pFramework->m_pddsBackBuffer, NULL, DDBLT_WAIT, NULL);
memset((void *)&ddsd2, 0, sizeof(ddsd2));
ddsd2.dwSize = sizeof(ddsd2);
m_pddsSurface->GetSurfaceDesc(&ddsd2);
if (m_pddsSurface->Lock(NULL, &ddsd2, DDLOCK_SURFACEMEMORYPTR, 0) != DD_OK)
{
return false;
}
unsigned char * pulMemorySnapShot = new unsigned char[ddsd2.dwWidth*ddsd2.dwHeight*3];
if (!pulMemorySnapShot)
{
danaeApp.m_pFramework->m_pddsBackBuffer->Unlock(NULL);
return false;
}
unsigned char * pulMemorySnapShotClone = pulMemorySnapShot;
unsigned char * pMemoryBase = (unsigned char *)ddsd2.lpSurface;
int iPitch = ddsd2.lPitch * (ddsd2.dwHeight - 1);
switch (ddsd2.ddpfPixelFormat.dwRGBBitCount)
{
case 16:
{
int iDecalR = 0;
int iDecalG = 0;
int iDecalB = 0;
int iDec;
iDec = ddsd2.ddpfPixelFormat.dwRBitMask;
while (!(iDec & 0x800000))
{
iDecalR++;
iDec <<= 1;
}
iDec = ddsd2.ddpfPixelFormat.dwGBitMask;
while (!(iDec & 0x8000))
{
iDec <<= 1;
iDecalG++;
}
iDec = ddsd2.ddpfPixelFormat.dwBBitMask;
while (!(iDec & 0x80))
{
iDec <<= 1;
iDecalB++;
}
for (unsigned int iY = 0; iY < ddsd2.dwHeight; iY++)
{
unsigned short * pMemory = (unsigned short *)(pMemoryBase + iPitch);
for (unsigned int iX = 0; iX < ddsd2.dwWidth; iX++)
{
unsigned int iColor = pMemory[iX];
int iR = (iColor & ddsd2.ddpfPixelFormat.dwRBitMask) << iDecalR;
int iG = (iColor & ddsd2.ddpfPixelFormat.dwGBitMask) << iDecalG;
int iB = (iColor & ddsd2.ddpfPixelFormat.dwBBitMask) << iDecalB;
ARX_CHECK_UCHAR(iB);
*pulMemorySnapShotClone++ = ARX_CLEAN_WARN_CAST_UCHAR(iB);
ARX_CHECK_UCHAR(iG >> 8);
*pulMemorySnapShotClone++ = ARX_CLEAN_WARN_CAST_UCHAR(iG >> 8);
ARX_CHECK_UCHAR(iR >> 16);
*pulMemorySnapShotClone++ = ARX_CLEAN_WARN_CAST_UCHAR(iR >> 16);
}
iPitch -= ddsd2.lPitch;
}
}
break;
case 24:
{
for (unsigned int iY = 0; iY < ddsd2.dwHeight; iY++)
{
unsigned char * pMemory = (unsigned char *)(pMemoryBase + iPitch);
for (unsigned int iX = 0; iX < ddsd2.dwWidth; iX++)
{
int iR = *pMemory++;
int iG = *pMemory++;
int iB = *pMemory++;
ARX_CHECK_UCHAR(iR);
*pulMemorySnapShotClone++ = ARX_CLEAN_WARN_CAST_UCHAR(iR);
ARX_CHECK_UCHAR(iG);
*pulMemorySnapShotClone++ = ARX_CLEAN_WARN_CAST_UCHAR(iG);
ARX_CHECK_UCHAR(iB);
*pulMemorySnapShotClone++ = ARX_CLEAN_WARN_CAST_UCHAR(iB);
}
iPitch -= ddsd2.lPitch;
}
}
break;
case 32:
{
for (unsigned int iY = 0; iY < ddsd2.dwHeight; iY++)
{
unsigned char * pMemory = (unsigned char *)(pMemoryBase + iPitch);
for (unsigned int iX = 0; iX < ddsd2.dwWidth; iX++)
{
int iR = *pMemory++;
int iG = *pMemory++;
int iB = *pMemory++;
pMemory++;
ARX_CHECK_UCHAR(iR);
*pulMemorySnapShotClone++ = ARX_CLEAN_WARN_CAST_UCHAR(iR);
ARX_CHECK_UCHAR(iG);
*pulMemorySnapShotClone++ = ARX_CLEAN_WARN_CAST_UCHAR(iG);
ARX_CHECK_UCHAR(iB);
*pulMemorySnapShotClone++ = ARX_CLEAN_WARN_CAST_UCHAR(iB);
}
iPitch -= ddsd2.lPitch;
}
}
break;
}
m_pddsSurface->Unlock(NULL);
m_pddsSurface->Release();
//sauvegarde bmp
char tTxt[256];
sprintf(tTxt, "%s%s_%d.bmp", Project.workingdir, pName, ulNum);
FILE * fFile = fopen(tTxt, "wb");
if (!fFile)
{
delete pulMemorySnapShot;
return false;
}
ulNum++;
BITMAPFILEHEADER bfhBitmapFileHeader;
bfhBitmapFileHeader.bfType = ('M' << 8) | ('B');
bfhBitmapFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + ((ddsd2.dwWidth * ddsd2.dwHeight) * 3);
bfhBitmapFileHeader.bfReserved1 = bfhBitmapFileHeader.bfReserved2 = 0;
bfhBitmapFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
fwrite(&bfhBitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, fFile);
BITMAPINFOHEADER bihBitmapInfoHeader;
bihBitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bihBitmapInfoHeader.biWidth = ddsd2.dwWidth;
bihBitmapInfoHeader.biHeight = ddsd2.dwHeight;
bihBitmapInfoHeader.biPlanes = 1;
bihBitmapInfoHeader.biBitCount = 24;
bihBitmapInfoHeader.biCompression = BI_RGB;
bihBitmapInfoHeader.biSizeImage = ((ddsd2.dwWidth * ddsd2.dwHeight) * 3);
bihBitmapInfoHeader.biXPelsPerMeter = 0;
bihBitmapInfoHeader.biYPelsPerMeter = 0;
bihBitmapInfoHeader.biClrUsed = 0;
bihBitmapInfoHeader.biClrImportant = 0;
fwrite(&bihBitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, fFile);
fwrite(pulMemorySnapShot, (ddsd2.dwWidth * ddsd2.dwHeight) * 3, 1, fFile);
fclose(fFile);
delete pulMemorySnapShot;
return true;
}
//-----------------------------------------------------------------------------
void InitSnapShot(char * _pDir, char * _pName)
{
FreeSnapShot();
pSnapShot = new SnapShot(_pDir, _pName);
}
//-----------------------------------------------------------------------------
void GetSnapShot()
{
if (pSnapShot)
{
pSnapShot->GetSnapShot();
}
}
//-----------------------------------------------------------------------------
void FreeSnapShot()
{
if (pSnapShot)
{
delete pSnapShot;
pSnapShot = NULL;
}
}