Skip to content

Commit

Permalink
Improvements
Browse files Browse the repository at this point in the history
-Add support for better bink video handling with Union/Systempack FixBink
-Scale heads with fatness value without depending on distance from camera
  • Loading branch information
SaiyansKing committed Nov 9, 2021
1 parent 4ba4d58 commit 1d670ac
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 58 deletions.
99 changes: 64 additions & 35 deletions D3D11Engine/D3D7/MyDirectDrawSurface7.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,12 @@ HRESULT MyDirectDrawSurface7::Lock( LPRECT lpDestRect, LPDDSURFACEDESC2 lpDDSurf
// Handle movie frame,
// don't deallocate the memory after unlock, since only the changing parts in videos will get updated
if ( !LockedData )
LockedData = new unsigned char[EngineTexture->GetSizeInBytes( 0 ) / divisor];
LockedData = new unsigned char[EngineTexture->GetSizeInBytes( 0 )];

// First movie frame - reset data
if ( Engine::GAPI->GetRendererState().RendererInfo.FirstVideoFrame ) {
memset( LockedData, 0, EngineTexture->GetSizeInBytes( 0 ) );
}
} else {
// Allocate some temporary data
delete[] LockedData;
Expand Down Expand Up @@ -442,46 +447,70 @@ HRESULT MyDirectDrawSurface7::Unlock( LPRECT lpRect ) {
delete[] dst;
} else {
if ( bpp == 24 ) {
// First movie frame - clear backbuffers
if ( Engine::GAPI->GetRendererState().RendererInfo.FirstVideoFrame ) {
Engine::GraphicsEngine->Clear( float4( 0.0f, 0.0f, 0.0f, 0.0f ) );
Engine::GAPI->GetRendererState().RendererInfo.FirstVideoFrame = 0;
}

if ( Engine::GAPI->GetRendererState().RendererInfo.FixBink ) {
// SSE2 BGRA -> RGBA conversion
__m128i mask = _mm_setr_epi8( -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0 );
int32_t textureDataSize = static_cast<int32_t>(EngineTexture->GetSizeInBytes( 0 )) - 32;
int32_t i = 0;
for ( ; i <= textureDataSize; i += 32 ) {
__m128i data0 = _mm_loadu_si128( reinterpret_cast<const __m128i*>(&LockedData[i]) );
__m128i data1 = _mm_loadu_si128( reinterpret_cast<const __m128i*>(&LockedData[i + 16]) );
__m128i gaComponents0 = _mm_andnot_si128( mask, data0 );
__m128i brComponents0 = _mm_and_si128( data0, mask );
__m128i gaComponents1 = _mm_andnot_si128( mask, data1 );
__m128i brComponents1 = _mm_and_si128( data1, mask );
__m128i brSwapped0 = _mm_shufflehi_epi16( _mm_shufflelo_epi16( brComponents0, _MM_SHUFFLE( 2, 3, 0, 1 ) ), _MM_SHUFFLE( 2, 3, 0, 1 ) );
__m128i brSwapped1 = _mm_shufflehi_epi16( _mm_shufflelo_epi16( brComponents1, _MM_SHUFFLE( 2, 3, 0, 1 ) ), _MM_SHUFFLE( 2, 3, 0, 1 ) );
_mm_storeu_si128( reinterpret_cast<__m128i*>(&LockedData[i]), _mm_or_si128( gaComponents0, brSwapped0 ) );
_mm_storeu_si128( reinterpret_cast<__m128i*>(&LockedData[i + 16]), _mm_or_si128( gaComponents1, brSwapped1 ) );
}
textureDataSize += 32;
for ( ; i < textureDataSize; i += 4 ) {
unsigned char R = LockedData[i + 0];
unsigned char G = LockedData[i + 2];
LockedData[i + 0] = G;
LockedData[i + 2] = R;
}
}

// This is a movie frame, draw it to the sceen
EngineTexture->UpdateData( LockedData, 0 );

EngineTexture->BindToPixelShader( 0 );

Engine::GAPI->GetRendererState().BlendState.SetDefault();
Engine::GAPI->GetRendererState().BlendState.SetDirty();

INT2 vidRes = Engine::GAPI->GetRendererState().RendererInfo.PlayingMovieResolution;

// Catch unset resolution
if ( vidRes.x == 0 || vidRes.y == 0 )
vidRes = Engine::GraphicsEngine->GetResolution();
const INT2 engineRes = Engine::GraphicsEngine->GetResolution();
/*FXMVECTOR mid = XMVectorSet( engineRes.x / 2, engineRes.y / 2, 0, 0 ); //never used
DirectX::XMFLOAT2 tl;
XMStoreFloat2( &tl, mid - XMVectorSet( vidRes.x, vidRes.y, 0, 0 ) * 0.5f );
DirectX::XMFLOAT2 br;
XMStoreFloat2( &br, mid + XMVectorSet( vidRes.x, vidRes.y, 0, 0 ) * 0.5f );*/

// Compute how much we would have to scale the video on both axis
float scaleX = engineRes.x / (float)vidRes.x;
float scaleY = engineRes.y / (float)vidRes.y;

// select the smaller one
float scale = std::min( scaleX, scaleY ) * 0.75f;

// I am honestly not sure how this is correct, but after an hour of fiddeling this works fine. You probably don't want to touch it.
float tlx = -engineRes.x * scale + (float)engineRes.x;
float tly = -engineRes.y * scale + (float)engineRes.y;

float brx = engineRes.x * scale;
float bry = engineRes.y * scale;

#if defined(BUILD_GOTHIC_2_6_fix) || defined(BUILD_GOTHIC_1_08k)
Engine::GraphicsEngine->DrawQuad( INT2( tlx, tly ),
INT2( brx - tlx, bry - tly ) );
#else
Engine::GraphicsEngine->DrawQuad( INT2( 0, 0 ),
Engine::GraphicsEngine->GetResolution() );
#endif
if ( Engine::GAPI->GetRendererState().RendererInfo.FixBink ) {
Engine::GraphicsEngine->DrawQuad( INT2( 0, 0 ), Engine::GraphicsEngine->GetResolution() );
} else {
INT2 vidRes = Engine::GAPI->GetRendererState().RendererInfo.PlayingMovieResolution;
if ( vidRes.x == 0 || vidRes.y == 0 )
vidRes = Engine::GraphicsEngine->GetResolution();

const INT2 engineRes = Engine::GraphicsEngine->GetResolution();

// Compute how much we would have to scale the video on both axis
float scaleX = engineRes.x / (float)vidRes.x;
float scaleY = engineRes.y / (float)vidRes.y;

// select the smaller one
float scale = std::min( scaleX, scaleY ) * 0.75f;

// I am honestly not sure how this is correct, but after an hour of fiddeling this works fine. You probably don't want to touch it.
float tlx = -engineRes.x * scale + (float)engineRes.x;
float tly = -engineRes.y * scale + (float)engineRes.y;

float brx = engineRes.x * scale;
float bry = engineRes.y * scale;

Engine::GraphicsEngine->DrawQuad( INT2( tlx, tly ), INT2( brx - tlx, bry - tly ) );
}
} else {
// No conversion needed
if ( Engine::GAPI->GetMainThreadID() != GetCurrentThreadId() ) {
Expand Down
47 changes: 43 additions & 4 deletions D3D11Engine/GothicAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ bool GetPrivateProfileBoolA(

/** Called when the game starts */
void GothicAPI::OnGameStart() {
LoadFixBinkValue();
LoadMenuSettings( MENU_SETTINGS_FILE );

LogInfo() << "Running with Commandline: " << zCOption::GetOptions()->GetCommandline();
Expand Down Expand Up @@ -1834,14 +1835,22 @@ void GothicAPI::DrawSkeletalMeshVob( SkeletalVobInfo* vi, float distance, bool u
}
}

if ( isMMS ) {
// Only 0.35f of the fatness wanted by gothic.
// They seem to compensate for that with the scaling.
instanceInfo.Fatness = std::max<float>( 0.f, fatness * 0.35f );
instanceInfo.Scaling = fatness * 0.02f + 1.f;
} else {
instanceInfo.Fatness = 0.f;
instanceInfo.Scaling = 1.f;
}

auto& VShader = g->GetActiveVS();
if ( distance < 1000 && isMMS ) {
zCMorphMesh* mm = (zCMorphMesh*)mvi->Visual;
// Only draw this as a morphmesh when rendering the main scene or when rendering as ghost
if ( g->GetRenderingStage() == DES_MAIN || g->GetRenderingStage() == DES_GHOST ) {
// Update constantbuffer
instanceInfo.Fatness = std::max<float>( 0.f, fatness * 0.35f );
instanceInfo.Scaling = fatness * 0.02f + 1.f;
instanceInfo.World = *(XMFLOAT4X4*)&RendererState.TransformState.TransformWorld;
VShader->GetConstantBuffer()[1]->UpdateBuffer( &instanceInfo );
VShader->GetConstantBuffer()[1]->BindToVertexShader( 1 );
Expand All @@ -1855,8 +1864,6 @@ void GothicAPI::DrawSkeletalMeshVob( SkeletalVobInfo* vi, float distance, bool u
}
}

instanceInfo.Fatness = 0.f;
instanceInfo.Scaling = 1.f;
instanceInfo.World = *(XMFLOAT4X4*)&RendererState.TransformState.TransformWorld;
VShader->GetConstantBuffer()[1]->UpdateBuffer( &instanceInfo );
VShader->GetConstantBuffer()[1]->BindToVertexShader( 1 );
Expand Down Expand Up @@ -3677,6 +3684,38 @@ XRESULT GothicAPI::LoadVegetation( const std::string& file ) {
return XR_SUCCESS;
}

/** Loads the FixBink value from SystemPack.ini */
void GothicAPI::LoadFixBinkValue() {
TCHAR NPath[MAX_PATH];
// Returns Gothic directory.
int len = GetCurrentDirectory( MAX_PATH, NPath );
// Get path to Gothic.Ini
auto ini = std::string( NPath, len ).append( "\\system\\SystemPack.ini" );

if ( !Toolbox::FileExists( ini ) ) {
return;
}

std::string FixBinkValue = GetPrivateProfileStringA( "DEBUG", "FixBink", "", ini );
if ( FixBinkValue == "1" || _stricmp( FixBinkValue.c_str(), "true" ) == 0 ) {
RendererState.RendererInfo.FixBink = 1;
}
}

/** Saves the window resolution to Gothic.ini */
void GothicAPI::SaveWindowResolution() {
TCHAR NPath[MAX_PATH];
// Returns Gothic directory.
int len = GetCurrentDirectory( MAX_PATH, NPath );
// Get path to Gothic.Ini
auto ini = std::string( NPath, len ).append( "\\system\\Gothic.ini" );

auto res = Engine::GraphicsEngine->GetResolution();
WritePrivateProfileStringA( "GAME", "scaleVideos", "1", ini.c_str() );
WritePrivateProfileStringA( "VIDEO", "zVidResFullscreenX", std::to_string( res.x ).c_str(), ini.c_str() );
WritePrivateProfileStringA( "VIDEO", "zVidResFullscreenY", std::to_string( res.y ).c_str(), ini.c_str() );
}

/** Saves the users settings from the menu */
XRESULT GothicAPI::SaveMenuSettings( const std::string& file ) {
TCHAR NPath[MAX_PATH];
Expand Down
6 changes: 6 additions & 0 deletions D3D11Engine/GothicAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,12 @@ class GothicAPI {
/** Returns the wetness of the scene. Lasts longer than RainFXWeight */
float GetSceneWetness();

/** Loads the FixBink value from SystemPack.ini */
void LoadFixBinkValue();

/** Saves the window resolution to Gothic.ini */
void SaveWindowResolution();

/** Saves the users settings from the menu */
XRESULT SaveMenuSettings( const std::string& file );

Expand Down
6 changes: 5 additions & 1 deletion D3D11Engine/GothicGraphicsState.h
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,8 @@ struct GothicRendererInfo {
GothicRendererInfo() {
VOBVerticesDataSize = 0;
SkeletalVerticesDataSize = 0;
FirstVideoFrame = 0;
FixBink = 0;
PlayingMovieResolution = INT2( 0, 0 );
Reset();
}
Expand Down Expand Up @@ -917,7 +919,9 @@ struct GothicRendererInfo {
unsigned int VOBVerticesDataSize;
unsigned int SkeletalVerticesDataSize;

/** Resolution of the currently playing video, only valid when a movie plays! */
/** Bink Video specific variables */
int FirstVideoFrame;
int FixBink;
INT2 PlayingMovieResolution;
};

Expand Down
32 changes: 15 additions & 17 deletions D3D11Engine/HookedFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,22 +294,23 @@ long __stdcall HookedFunctionInfo::hooked_zCExceptionHandlerUnhandledExceptionFi

/** Returns the pixelformat of a bink-surface */
long __fastcall HookedFunctionInfo::hooked_zBinkPlayerGetPixelFormat( void* thisptr, void* unknwn, zTRndSurfaceDesc& desc ) {
int* cd = (int*)&desc;

// Resolution is at pos [2] and [3]
//cd[2] = Engine::GraphicsEngine->GetResolution().x;
//cd[3] = Engine::GraphicsEngine->GetResolution().y;

/*for(int i=0;i<0x7C;i++)
{
cd[i] = i;
}*/
// Return values seems to be:
// 3 - bgra
// 4 - rgba

// Union/Systempack FixBink seems to work only with bgra format
if ( Engine::GAPI->GetRendererState().RendererInfo.FixBink )
return 3;

return 4; // 4 satisfies gothic enough to play the video
//Global::HookedFunctions.zBinkPlayerGetPixelFormat(thisptr, desc);
// Use rgba format with disabled FixBink because for some reason there seem to be some ugly graphical glitches
return 4;
}

int __fastcall HookedFunctionInfo::hooked_zBinkPlayerOpenVideo( void* thisptr, void* unknwn, zSTRING str ) {
// Need to save window resolution before starting video
// Union/Systempack reads these values from Gothic.ini when opening video
Engine::GAPI->SaveWindowResolution();
Engine::GAPI->GetRendererState().RendererInfo.FirstVideoFrame = 1;
int r = HookedFunctions::OriginalFunctions.original_zCBinkPlayerOpenVideo( thisptr, str );

struct BinkInfo {
Expand All @@ -321,22 +322,19 @@ int __fastcall HookedFunctionInfo::hooked_zBinkPlayerOpenVideo( void* thisptr, v
// Grab the resolution
// This structure stores width and height as first two parameters, as ints.
BinkInfo* res = *(BinkInfo**)(((char*)thisptr) + (GothicMemoryLocations::zCBinkPlayer::Offset_VideoHandle));

if ( res ) {
Engine::GAPI->GetRendererState().RendererInfo.PlayingMovieResolution = INT2( res->ResX, res->ResY );
}

return r;
}

int __cdecl HookedFunctionInfo::hooked_GetNumDevices()
{
int __cdecl HookedFunctionInfo::hooked_GetNumDevices() {
Engine::GraphicsEngine->OnUIEvent( BaseGraphicsEngine::EUIEvent::UI_OpenSettings );
return 1;
}

void __fastcall HookedFunctionInfo::hooked_SetLightmap( void* polygonPtr )
{
void __fastcall HookedFunctionInfo::hooked_SetLightmap( void* polygonPtr ) {
static zCLightmap* lightmap = nullptr;
if ( !lightmap ) {
#ifdef BUILD_GOTHIC_1_08k
Expand Down
2 changes: 1 addition & 1 deletion D3D11Engine/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#define stdext std
#endif

#define VERSION_NUMBER "17.7-dev27"
#define VERSION_NUMBER "17.7-dev28"
__declspec(selectany) const char* VERSION_NUMBER_STR = VERSION_NUMBER;

extern bool FeatureLevel10Compatibility;
Expand Down

0 comments on commit 1d670ac

Please sign in to comment.