mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
[HRP] Fixed the screenshot for sfall DX9 mode
* Now the screenshots are saved in PNG format. [HRP] Adjusted the position of movie subtitles. [TEST] Changed the DirectX 9 device creation mode.
This commit is contained in:
+2
-1
@@ -95,6 +95,7 @@ Use32BitHeadGraphics=0
|
||||
;Set to 1 to automatically search for alternative AVI video files when Fallout tries to play the game movies
|
||||
;Set to 2 to force AVI videos to fit the screen width
|
||||
;Requires DX9 graphics mode
|
||||
;The recommended video codec is Xvid
|
||||
AllowDShowMovies=0
|
||||
|
||||
;Fade effect time percentage modifier
|
||||
@@ -331,7 +332,7 @@ Movie17=credits.mve
|
||||
|
||||
;To change the limit of the distance away from the player to which you're allowed to scroll the local maps, uncomment the next two lines
|
||||
;Defaults are 480 in the x direction and 400 in the y direction.
|
||||
;Not compatible with the res patch!
|
||||
;Not compatible with the hi-res patch!
|
||||
;LocalMapXLimit=480
|
||||
;LocalMapYLimit=400
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ void Render::init() {
|
||||
|
||||
// Custom implementation of the GNW_win_refresh function
|
||||
sf::MakeJump(0x4D6FD9, GNW_win_refresh_hack, 1);
|
||||
// Replace _screendump_buf with _screen_buffer for creating screenshots
|
||||
// Replace _screendump_buf with _screen_buffer for creating screenshots (for sfall DX9 mode with HRP by Mash)
|
||||
sf::SafeWriteBatch<DWORD>(FO_VAR_screen_buffer, {0x4C8FD1, 0x4C900D});
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ static void __fastcall SetMovieSize() {
|
||||
|
||||
if (MoviesScreen::MOVIE_SIZE == 1 || bW > sWidth || bH > sHeight) {
|
||||
long aspectW = sWidth;
|
||||
long aspectH = sHeight - subtitleHeight;
|
||||
long aspectH = sHeight;
|
||||
long x = 0;
|
||||
long y = 0;
|
||||
Image::GetAspectSize(bW, bH, &x, &y, aspectW, aspectH);
|
||||
@@ -100,7 +100,7 @@ static void __cdecl movieShowFrame(IDirectDrawSurface7* surface, int bW, int bH,
|
||||
if (!win) return;
|
||||
|
||||
DDSURFACEDESC2 desc;
|
||||
desc.dwSize = sizeof(DDSURFACEDESC);
|
||||
desc.dwSize = sizeof(DDSURFACEDESC2);
|
||||
surface->Lock(0, &desc, DDLOCK_WAIT, 0);
|
||||
|
||||
BYTE* dst = win->surface + movieToSize.left + (movieToSize.top * win->width);
|
||||
@@ -117,7 +117,7 @@ static long __fastcall SubtitleAdjustPosition(long yTop, long yBottom) {
|
||||
if (MoviesScreen::MOVIE_SIZE == 0 || Setting::ScreenHeight() == 480) return yTop;
|
||||
|
||||
long y = fo::var::getInt(FO_VAR_lastMovieY);
|
||||
y += fo::var::getInt(FO_VAR_lastMovieH) + 4;
|
||||
y += fo::var::getInt(FO_VAR_lastMovieH);// + 4;
|
||||
|
||||
if (yTop >= y) return yTop;
|
||||
|
||||
|
||||
+129
-5
@@ -21,6 +21,7 @@
|
||||
#include "..\WinProc.h"
|
||||
#include "LoadGameHook.h"
|
||||
#include "ScriptShaders.h"
|
||||
#include "Movies.h"
|
||||
|
||||
#include "SubModules\DirectDraw.h"
|
||||
#include "SubModules\WindowRender.h"
|
||||
@@ -69,6 +70,7 @@ bool Graphics::IsWindowedMode;
|
||||
|
||||
bool Graphics::PlayAviMovie = false;
|
||||
bool Graphics::AviMovieWidthFit = false;
|
||||
static bool dShowMovies;
|
||||
|
||||
bool DeviceLost = false;
|
||||
static char textureFilter; // 1 - auto, 2 - force
|
||||
@@ -185,12 +187,14 @@ static void ResetDevice(bool create) {
|
||||
static D3DFORMAT textureFormat = D3DFMT_X8R8G8B8;
|
||||
|
||||
if (create) {
|
||||
DWORD mThreadFlags = (dShowMovies) ? D3DCREATE_MULTITHREADED : 0;
|
||||
|
||||
dlog("Creating D3D9 Device...", DL_MAIN);
|
||||
if (FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, D3DCREATE_PUREDEVICE | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE, ¶ms, &d3d9Device))) {
|
||||
if (FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, D3DCREATE_HARDWARE_VERTEXPROCESSING | mThreadFlags, ¶ms, &d3d9Device))) { //D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE
|
||||
MessageBoxA(window, "Failed to create hardware vertex processing device.\nUsing software vertex processing instead.",
|
||||
"sfall DX9", MB_TASKMODAL | MB_ICONWARNING);
|
||||
"sfall DirectX 9", MB_TASKMODAL | MB_ICONWARNING);
|
||||
software = true;
|
||||
d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE, ¶ms, &d3d9Device);
|
||||
d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, D3DCREATE_SOFTWARE_VERTEXPROCESSING | mThreadFlags, ¶ms, &d3d9Device); //D3DCREATE_FPU_PRESERVE
|
||||
}
|
||||
|
||||
D3DCAPS9 caps;
|
||||
@@ -224,7 +228,7 @@ static void ResetDevice(bool create) {
|
||||
textureFormat = (A8IsSupported) ? D3DFMT_A8 : D3DFMT_L8; // D3DFMT_A8 - not supported on some older video cards
|
||||
} else {
|
||||
MessageBoxA(window, "Failed to create shader effects.\nSwitching to CPU for the palette conversion.",
|
||||
"sfall DX9", MB_TASKMODAL | MB_ICONWARNING);
|
||||
"sfall DirectX 9", MB_TASKMODAL | MB_ICONWARNING);
|
||||
if (mainTex) SAFERELEASE(mainTex); // release D3DFMT_A8 format texture
|
||||
Graphics::GPUBlt = 0;
|
||||
A8IsSupported = false;
|
||||
@@ -236,7 +240,7 @@ static void ResetDevice(bool create) {
|
||||
d3d9Device->CreateTexture(ResWidth, ResHeight, 1, 0, textureFormat, D3DPOOL_SYSTEMMEM, &mainTex, 0);
|
||||
MessageBoxA(window, "Texture format error.\nGPU does not support the D3DFMT_L8 texture format.\nNow CPU is used to convert the palette.\n"
|
||||
"Set 'GPUBlt' option to CPU to bypass this warning message.",
|
||||
"sfall DX9", MB_TASKMODAL | MB_ICONWARNING);
|
||||
"sfall DirectX 9", MB_TASKMODAL | MB_ICONWARNING);
|
||||
Graphics::GPUBlt = 0;
|
||||
}
|
||||
if (Graphics::GPUBlt == 0) palette = new DirectDraw::PALCOLOR[256];
|
||||
@@ -649,7 +653,9 @@ public:
|
||||
int height = mveDesc.dwHeight;
|
||||
|
||||
if (d != 0) { // scale
|
||||
//mveScaleSurface = (BYTE*)fo::var::getInt(FO_VAR_screen_buffer);
|
||||
if (!mveScaleSurface) mveScaleSurface = new BYTE[ResWidth * ResHeight];
|
||||
|
||||
width = dst->right - dst->left;
|
||||
height = dst->bottom - dst->top;
|
||||
|
||||
@@ -1186,6 +1192,118 @@ void Graphics::BackgroundClearColor(long indxColor) {
|
||||
std::memset(desc.lpSurface, indxColor, ResWidth * ResHeight);
|
||||
}
|
||||
}
|
||||
/*
|
||||
#pragma pack(push, 1)
|
||||
struct BMPHEADER {
|
||||
BITMAPFILEHEADER bFile;
|
||||
BITMAPINFOHEADER bInfo;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
*/
|
||||
long __stdcall SaveScreen(const char* file) {
|
||||
IDirect3DSurface9* surface;
|
||||
d3d9Device->CreateOffscreenPlainSurface(gWidth, gHeight, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &surface, 0);
|
||||
d3d9Device->GetRenderTargetData(backBuffer, surface);
|
||||
|
||||
LPD3DXBUFFER buffer;
|
||||
D3DXCreateBuffer(gWidth * gHeight * 2, &buffer);
|
||||
|
||||
D3DXSaveSurfaceToFileInMemory(&buffer, D3DXIFF_PNG, surface, 0, 0);
|
||||
//D3DXSaveSurfaceToFileA(file, D3DXIFF_PNG, surface, 0, 0); // slow save
|
||||
|
||||
HANDLE hFile = CreateFileA(file, GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
bool resultOK = (hFile != INVALID_HANDLE_VALUE);
|
||||
if (resultOK) {
|
||||
DWORD dwWritten;
|
||||
WriteFile(hFile, buffer->GetBufferPointer(), buffer->GetBufferSize(), &dwWritten, 0);
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
surface->Release();
|
||||
buffer->Release();
|
||||
|
||||
/* BMP 24-bit
|
||||
long bmpExtraSize = gWidth * 3 % 4;
|
||||
if (bmpExtraSize != 0) bmpExtraSize = 4 - bmpExtraSize;
|
||||
|
||||
DWORD sizeImage = gWidth * gHeight * 3;
|
||||
sizeImage += gHeight * bmpExtraSize;
|
||||
|
||||
BMPHEADER bmpHeader;
|
||||
std::memset(&bmpHeader, 0, sizeof(BMPHEADER));
|
||||
|
||||
bmpHeader.bFile.bfType = 0x4D42;
|
||||
bmpHeader.bFile.bfOffBits = sizeof(BMPHEADER);
|
||||
bmpHeader.bInfo.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmpHeader.bInfo.biWidth = gWidth;
|
||||
bmpHeader.bInfo.biHeight = 0 - gHeight;
|
||||
bmpHeader.bInfo.biPlanes = 1;
|
||||
bmpHeader.bInfo.biBitCount = 24;
|
||||
bmpHeader.bInfo.biCompression = BI_RGB;
|
||||
bmpHeader.bInfo.biSizeImage = sizeImage;
|
||||
|
||||
BYTE* bmpImageData = new BYTE[sizeImage];
|
||||
BYTE* dData = bmpImageData;
|
||||
|
||||
D3DLOCKED_RECT lockRect;
|
||||
surface->LockRect(&lockRect, 0, 0);
|
||||
BYTE* lockData = (BYTE*)lockRect.pBits;
|
||||
|
||||
// 32-bit to 24-bit
|
||||
for (size_t h = 0; h < gHeight; h++) {
|
||||
BYTE* sData = lockData;
|
||||
for (size_t x = 0; x < gWidth; x++) {
|
||||
*dData++ = *sData++;
|
||||
*dData++ = *sData++;
|
||||
*dData++ = *sData++;
|
||||
sData++;
|
||||
}
|
||||
lockData += lockRect.Pitch;
|
||||
dData += bmpExtraSize;
|
||||
}
|
||||
|
||||
surface->UnlockRect();
|
||||
surface->Release();
|
||||
|
||||
HANDLE hFile = CreateFileA(file, GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
bool resultOK = (hFile != INVALID_HANDLE_VALUE);
|
||||
|
||||
if (resultOK) {
|
||||
DWORD dwWritten;
|
||||
WriteFile(hFile, &bmpHeader, sizeof(BMPHEADER), &dwWritten, 0);
|
||||
WriteFile(hFile, bmpImageData, sizeImage, &dwWritten, 0);
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
delete[] bmpImageData;*/
|
||||
|
||||
return (resultOK) ? 0 : 1;
|
||||
}
|
||||
|
||||
long __stdcall game_screendump_hook() {
|
||||
char fileName[16];
|
||||
|
||||
for (size_t i = 0; i < 100000; i++) {
|
||||
std::sprintf(fileName, "scr%.5d.png", i); // scr#####.png
|
||||
|
||||
HANDLE hFile = CreateFileA(fileName, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
return SaveScreen(fileName);
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static __declspec(naked) void dump_screen_hack_replacement() {
|
||||
__asm {
|
||||
push ecx;
|
||||
push edx;
|
||||
call fo::funcoffs::game_screendump_; // call ds:[FO_VAR_screendump_func];
|
||||
pop edx;
|
||||
pop ecx;
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::init() {
|
||||
int gMode = IniReader::GetConfigInt("Graphics", "Mode", 0);
|
||||
@@ -1215,6 +1333,10 @@ void Graphics::init() {
|
||||
MakeJump(fo::funcoffs::GNW95_SetPaletteEntries_ + 1, GNW95_SetPaletteEntries_replacement); // 0x4CB311
|
||||
MakeJump(fo::funcoffs::GNW95_SetPalette_, GNW95_SetPalette_replacement); // 0x4CB568
|
||||
|
||||
// Replace the screenshot saving implementation for sfall DirectX 9
|
||||
HookCall(0x443EF3, game_screendump_hook);
|
||||
MakeJump(0x4C8F4C, dump_screen_hack_replacement);
|
||||
|
||||
if (HRP::Setting::VersionIsValid) {
|
||||
// Patch HRP to show the mouse cursor over the window title
|
||||
if (Graphics::mode == 5) SafeWrite8(HRP::Setting::GetAddress(0x10027142), CodeType::JumpShort);
|
||||
@@ -1226,6 +1348,8 @@ void Graphics::init() {
|
||||
textureFilter = IniReader::GetConfigInt("Graphics", "TextureFilter", 1);
|
||||
dlogr(" Done", DL_INIT);
|
||||
|
||||
dShowMovies = Movies::DirectShowMovies();
|
||||
|
||||
LoadGameHook::OnGameReset() += []() {
|
||||
ForceGraphicsRefresh(0); // disable refresh
|
||||
};
|
||||
|
||||
@@ -41,7 +41,6 @@ static DWORD __fastcall CalcDeathAnimHook_Script(DWORD damage, fo::GameObject* t
|
||||
DWORD animDeath = fo::func::pick_death(attacker, target, weapon, damage, animation, hitBack); // vanilla pick death
|
||||
|
||||
if (registerHookDeathAnim2) {
|
||||
//argCount = 5;
|
||||
args[4] = animDeath;
|
||||
RunHookScript(HOOK_DEATHANIM2);
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
#include "..\..\FalloutEngine\Fallout2.h"
|
||||
#include "..\..\SafeWrite.h"
|
||||
#include "..\HookScripts.h"
|
||||
|
||||
@@ -2,21 +2,23 @@
|
||||
|
||||
namespace sfall
|
||||
{
|
||||
void InitMiscHookScripts();
|
||||
void SourceUseSkillOnInit();
|
||||
|
||||
void Inject_BarterPriceHook();
|
||||
void Inject_UseSkillOnHook();
|
||||
void Inject_UseSkillHook();
|
||||
void Inject_StealCheckHook();
|
||||
void Inject_SneakCheckHook();
|
||||
void Inject_WithinPerceptionHook();
|
||||
void Inject_CarTravelHook();
|
||||
void Inject_SetGlobalVarHook();
|
||||
void Inject_RestTimerHook();
|
||||
void Inject_ExplosiveTimerHook();
|
||||
void Inject_EncounterHook();
|
||||
void Inject_RollCheckHook();
|
||||
void InitMiscHookScripts();
|
||||
void SourceUseSkillOnInit();
|
||||
|
||||
void Inject_BarterPriceHook();
|
||||
void Inject_UseSkillOnHook();
|
||||
void Inject_UseSkillHook();
|
||||
void Inject_StealCheckHook();
|
||||
void Inject_SneakCheckHook();
|
||||
void Inject_WithinPerceptionHook();
|
||||
void Inject_CarTravelHook();
|
||||
void Inject_SetGlobalVarHook();
|
||||
void Inject_RestTimerHook();
|
||||
void Inject_ExplosiveTimerHook();
|
||||
void Inject_EncounterHook();
|
||||
void Inject_RollCheckHook();
|
||||
|
||||
long PerceptionRangeHook_Invoke(fo::GameObject* watcher, fo::GameObject* target, long type, long result);
|
||||
|
||||
long PerceptionRangeHook_Invoke(fo::GameObject* watcher, fo::GameObject* target, long type, long result);
|
||||
}
|
||||
|
||||
@@ -2,17 +2,19 @@
|
||||
|
||||
namespace sfall
|
||||
{
|
||||
void InitObjectHookScripts();
|
||||
|
||||
void Inject_UseObjOnHook();
|
||||
void Inject_UseObjHook();
|
||||
void Inject_UseAnimateObjHook();
|
||||
void Inject_DescriptionObjHook();
|
||||
void Inject_SetLightingHook();
|
||||
void Inject_ScriptProcedureHook();
|
||||
void Inject_ScriptProcedureHook2();
|
||||
void Inject_AdjustPoisonHook();
|
||||
void Inject_AdjustRadsHook();
|
||||
void InitObjectHookScripts();
|
||||
|
||||
void Inject_UseObjOnHook();
|
||||
void Inject_UseObjHook();
|
||||
void Inject_UseAnimateObjHook();
|
||||
void Inject_DescriptionObjHook();
|
||||
void Inject_SetLightingHook();
|
||||
void Inject_ScriptProcedureHook();
|
||||
void Inject_ScriptProcedureHook2();
|
||||
void Inject_AdjustPoisonHook();
|
||||
void Inject_AdjustRadsHook();
|
||||
|
||||
long UseObjOnHook_Invoke(fo::GameObject* source, fo::GameObject* item, fo::GameObject* target);
|
||||
|
||||
long UseObjOnHook_Invoke(fo::GameObject* source, fo::GameObject* item, fo::GameObject* target);
|
||||
}
|
||||
|
||||
+17
-16
@@ -85,6 +85,7 @@ private:
|
||||
|
||||
lpAllocInfo->dwFlags |= VMR9AllocFlag_TextureSurface; // | VMR9AllocFlag_DXVATarget;
|
||||
lpAllocInfo->Pool = D3DPOOL_SYSTEMMEM;
|
||||
//lpAllocInfo->Format = D3DFMT_X8R8G8B8;
|
||||
|
||||
// Ask the VMR-9 to allocate the surfaces for us.
|
||||
for (auto &surface : surfaces) SAFERELEASE(surface);
|
||||
@@ -557,6 +558,22 @@ static __declspec(naked) void LostFocus() {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
WIP: Task
|
||||
Implement subtitle output from the need to play an mve file in the background.
|
||||
*/
|
||||
bool Movies::DirectShowMovies() {
|
||||
int allowDShowMovies = IniReader::GetConfigInt("Graphics", "AllowDShowMovies", 0);
|
||||
if (allowDShowMovies > 0) {
|
||||
Graphics::AviMovieWidthFit = (allowDShowMovies >= 2);
|
||||
MakeJump(0x44E690, gmovie_play_hack);
|
||||
HookCall(0x44E993, gmovie_play_hook_stop);
|
||||
/* NOTE: At this address 0x487781 (movieStart_), HRP by Mash changes the callback procedure to display mve frames. */
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Movies::init() {
|
||||
dlog("Applying movie patch.", DL_INIT);
|
||||
|
||||
@@ -576,25 +593,9 @@ void Movies::init() {
|
||||
IniReader::GetConfigString("Misc", optName, "", &MoviePaths[index], 65);
|
||||
}
|
||||
}
|
||||
dlog(".", DL_INIT);
|
||||
SafeWriteBatch<DWORD>((DWORD)MoviePtrs, {0x44E6AE, 0x44E721, 0x44E75E, 0x44E78A}); // gmovie_play_
|
||||
MakeCall(0x44E896, gmovie_play_hack_subpal, 2);
|
||||
MakeCall(0x45A1C9, op_play_gmovie_hack);
|
||||
dlog(".", DL_INIT);
|
||||
|
||||
/*
|
||||
WIP: Task
|
||||
Implement subtitle output from the need to play an mve file in the background.
|
||||
*/
|
||||
if (Graphics::mode >= 4) {
|
||||
int allowDShowMovies = IniReader::GetConfigInt("Graphics", "AllowDShowMovies", 0);
|
||||
if (allowDShowMovies > 0) {
|
||||
Graphics::AviMovieWidthFit = (allowDShowMovies >= 2);
|
||||
MakeJump(0x44E690, gmovie_play_hack);
|
||||
HookCall(0x44E993, gmovie_play_hook_stop);
|
||||
/* NOTE: At this address 0x487781 (movieStart_), HRP changes the callback procedure to display mve frames. */
|
||||
}
|
||||
}
|
||||
dlogr(" Done", DL_INIT);
|
||||
|
||||
DWORD days = SimplePatch<DWORD>(0x4A36EC, "Misc", "MovieTimer_artimer4", 360, 0);
|
||||
|
||||
@@ -28,6 +28,8 @@ public:
|
||||
const char* name() { return "Movies"; }
|
||||
void init();
|
||||
//void exit() override;
|
||||
|
||||
static bool DirectShowMovies();
|
||||
};
|
||||
|
||||
static constexpr int MaxMovies = 32;
|
||||
|
||||
Reference in New Issue
Block a user