and though bugs are the bane of my existence, rest assured the wretched thing will get the best of care here

...
 
Commits (4)
......@@ -19,11 +19,12 @@ set(SOURCES
game/ModelInfo.cpp
game/Clock.cpp
game/Vector.cpp
game/Game.cpp
game/Shadows.cpp
game_patches/material_system_patches.cpp
game_patches/rwd3d8_patches.cpp
game_patches/base_model_pipeline.cpp
game_patches/skin_model_pipeline.cpp
)
game_patches/skin_model_pipeline.cpp)
#set ( CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON )
......
#include "game/Renderer.h"
#include "game/Shadows.h"
#include "game_patches/base_model_pipeline.h"
#include "game_patches/material_system_patches.h"
#include "game_patches/rwd3d8_patches.h"
......@@ -42,8 +43,6 @@ int32_t AddPtLight( char a1, float x, float y, float z, float dx, int dy,
return 1;
}
BOOL emptystuff() { return false; }
BOOL WINAPI DllMain( HINSTANCE hModule, DWORD ul_reason_for_call,
LPVOID lpReserved )
{
......@@ -111,6 +110,7 @@ BOOL WINAPI DllMain( HINSTANCE hModule, DWORD ul_reason_for_call,
PatchMaterialSystem();
RwD3D8Patches::Patch();
Renderer::Patch();
Shadows::Patch();
// Im3D
// SetPointer( 0x6DF754, reinterpret_cast<void *>( rxD3D8SubmitNode ) );
......@@ -124,8 +124,6 @@ BOOL WINAPI DllMain( HINSTANCE hModule, DWORD ul_reason_for_call,
// RedirectCall( 0x4A65AE, reinterpret_cast<void *>( water_render ) );
// RedirectCall( 0x4CA267, reinterpret_cast<void *>( emptystuff ) );
// Buggy cutscene shadows
RedirectJump( 0x625D80, reinterpret_cast<void *>( emptystuff ) );
// Lights
RedirectJump( 0x567700, reinterpret_cast<void *>( AddPtLight ) );
......
//
// Created by peter on 28.02.2021.
//
#include "Game.h"
uint32_t &Game::CurrentArea = *reinterpret_cast<uint32_t *>( 0x978810 );
\ No newline at end of file
//
// Created by peter on 28.02.2021.
//
#pragma once
#include <cstdint>
class Game
{
public:
static uint32_t &CurrentArea;
};
\ No newline at end of file
......@@ -8,7 +8,7 @@
BaseModelInfo **ModelInfo::mModelInfoPtrs =
reinterpret_cast<BaseModelInfo **>( 0x92D4C8 );
RpAtomic *SimpleModelInfo::GetAtomicFromDistance( float d )
RpAtomic *SimpleModelInfo::GetAtomicFromDistance( float d ) const
{
d /= 4.0f;
for ( int i = mIsDamaged ? mFirstDamaged : 0; i < mNumAtomics; i++ )
......@@ -16,3 +16,10 @@ RpAtomic *SimpleModelInfo::GetAtomicFromDistance( float d )
return mAtomics[i];
return nullptr;
}
RpAtomic *SimpleModelInfo::GetFirstAtomicFromDistance( float d ) const
{
if ( d < mLodDistances[0] * 4.0f )
return mAtomics[0];
return nullptr;
}
......@@ -13,10 +13,11 @@ enum ModeInfoType : uint8_t
MITYPE_SIMPLE = 1,
MITYPE_MLO = 2,
MITYPE_TIME = 3,
MITYPE_CLUMP = 4,
MITYPE_VEHICLE = 5,
MITYPE_PED = 6,
MITYPE_XTRACOMPS = 7,
MITYPE_WEAPON = 4,
MITYPE_CLUMP = 5,
MITYPE_VEHICLE = 6,
MITYPE_PED = 7,
MITYPE_XTRACOMPS = 8,
};
class BaseModelInfo
......@@ -57,7 +58,8 @@ class SimpleModelInfo : public BaseModelInfo
uint16_t mIsSubway : 1;
uint16_t mIgnoreLight : 1;
uint16_t mNoZWrite : 1;
RpAtomic * GetAtomicFromDistance( float d );
RpAtomic * GetAtomicFromDistance( float d ) const;
RpAtomic * GetFirstAtomicFromDistance( float d ) const;
SimpleModelInfo *GetRelatedModel( void )
{
return (SimpleModelInfo *)mAtomics[2];
......
......@@ -4,6 +4,7 @@
#include "Renderer.h"
#include "Clock.h"
#include "Game.h"
#include "ModelInfo.h"
#include "Streaming.h"
#include <cmath>
......@@ -116,203 +117,186 @@ void Renderer::ScanSectorList( const WorldSector &sector )
}
}
int32_t Renderer::SetupEntityVisibility( Entity *ent )
int32_t Renderer::SetupSimpleModelVisibility( Entity & entity,
SimpleModelInfo &model_info )
{
auto *base_mi = ModelInfo::GetModelInfo( ent->mModelIndex );
if ( ent->bDrawLast )
if ( !( entity.mArea == Game::CurrentArea || entity.mArea == 13 ) )
return VIS_INVISIBLE;
if ( base_mi->mType != MITYPE_SIMPLE && base_mi->mType != MITYPE_TIME )
{
if ( ent->mRwObject == nullptr )
return VIS_STREAMME;
return ent->bIsVisible ? VIS_VISIBLE : VIS_INVISIBLE;
}
auto * mi = static_cast<SimpleModelInfo *>( base_mi );
TimeModelInfo * ti;
SimpleModelInfo *other;
float dist;
// bool request = true;
float dist = length( entity.mMatrix.m_matrix.pos - mCameraPosition );
if ( mi->mType == MITYPE_TIME )
{
ti = static_cast<TimeModelInfo *>( mi );
other = ti->mOtherTimeModel;
if ( Clock::GetIsTimeInRange( ti->mTimeOn, ti->mTimeOff ) )
{
// don't fade in, or between time objects
ti->mAlpha = 255;
}
else
{
// Hide if possible
return VIS_INVISIBLE;
}
}
else
if ( RpAtomic *atomic = model_info.GetAtomicFromDistance( dist ); atomic )
{
/*if ( mi->m_type != MITYPE_SIMPLE )
{
if ( FindPlayerVehicle() == ent &&
TheCamera.Cams[TheCamera.ActiveCam].Mode ==
CCam::MODE_1STPERSON )
{
// Player's vehicle in first person mode
if ( TheCamera.Cams[TheCamera.ActiveCam].DirectionWasLooking ==
LOOKING_FORWARD ||
ent->GetModelIndex() == MI_RHINO ||
ent->GetModelIndex() == MI_COACH ||
TheCamera.m_bInATunnelAndABigVehicle )
{
ent->bNoBrightHeadLights = true;
}
else
{
m_pFirstPersonVehicle = (CVehicle *)ent;
ent->bNoBrightHeadLights = false;
}
return VIS_OFFSCREEN;
}
else
{
// All sorts of Clumps
if ( ent->m_rwObject == nil || !ent->bIsVisible )
return VIS_INVISIBLE;
if ( !ent->GetIsOnScreen() )
return VIS_OFFSCREEN;
if ( ent->bDrawLast )
{
dist = ( ent->GetPosition() - ms_vecCameraPosition )
.Magnitude();
CVisibilityPlugins::InsertEntityIntoSortedList( ent, dist );
ent->bDistanceFade = false;
return VIS_INVISIBLE;
}
else
return VIS_VISIBLE;
}
return VIS_INVISIBLE;
}*/
/*if ( ent->m_type == ENTITY_TYPE_OBJECT &&
( (CObject *)ent )->ObjectCreatedBy == TEMP_OBJECT )
{
if ( ent->mRwObject == nullptr || !ent->bIsVisible )
return VIS_INVISIBLE;
return ent->GetIsOnScreen() ? VIS_VISIBLE : VIS_OFFSCREEN;
}*/
if ( ent->bDontStream )
{
if ( ent->mRwObject == nullptr || !ent->bIsVisible )
return VIS_INVISIBLE;
return VIS_VISIBLE;
}
}
model_info.mIsDamaged = false;
// Simple ModelInfo
if ( entity.mRwObject == nullptr )
entity.CreateRwObject();
assert( entity.mRwObject );
dist = length( ent->mMatrix.m_matrix.pos - mCameraPosition );
auto *rwobj = (RpAtomic *)entity.mRwObject;
// This can only happen with multi-atomic models (e.g. railtracks)
// but why do we bump up the distance? can only be fading...
/*if ( LOD_DISTANCE + STREAM_DISTANCE < dist &&
dist < mi->GetLargestLodDistance() )
dist = mi->GetLargestLodDistance();*/
// if ( ent->mType == ENTITY_TYPE_OBJECT && ent->bRenderDamaged )
// mi->mIsDamaged = true;
RpAtomic *a = mi->GetAtomicFromDistance( dist );
if ( a )
{
mi->mIsDamaged = false;
if ( ent->mRwObject == nullptr )
ent->CreateRwObject();
assert( ent->mRwObject );
auto *rwobj = (RpAtomic *)ent->mRwObject;
// Make sure our atomic uses the right geometry and not
// that of an atomic for another draw distance.
if ( a->geometry != rwobj->geometry )
RpAtomicSetGeometry( rwobj, a->geometry,
if ( atomic->geometry != rwobj->geometry )
RpAtomicSetGeometry( rwobj, atomic->geometry,
/*rpATOMICSAMEBOUNDINGSPHERE*/ 0x1 );
mi->IncreaseAlpha();
if ( ent->mRwObject == nullptr || !ent->bIsVisible )
return VIS_INVISIBLE;
model_info.IncreaseAlpha();
/*if ( !ent->GetIsOnScreen() )
{
mi->m_alpha = 255;
return VIS_OFFSCREEN;
}*/
if ( entity.mRwObject == nullptr || !entity.bIsVisible )
return VIS_INVISIBLE;
if ( mi->mAlpha != 255 )
if ( model_info.mAlpha != 0xFF )
{
// CVisibilityPlugins::InsertEntityIntoSortedList( ent, dist );
ent->bDistanceFade = true;
// return VIS_INVISIBLE;
entity.bDistanceFade = true;
return VIS_INVISIBLE;
}
/*if ( mi->m_drawLast || ent->bDrawLast )
{
CVisibilityPlugins::InsertEntityIntoSortedList( ent, dist );
ent->bDistanceFade = false;
return VIS_INVISIBLE;
}*/
return VIS_VISIBLE;
}
// Object is not loaded, figure out what to do
if ( mi->mNoFade )
if ( model_info.mNoFade )
{
mi->mIsDamaged = false;
// request model
// if ( dist - STREAM_DISTANCE < mi->GetLargestLodDistance() &&
// request
// )
model_info.mIsDamaged = false;
return VIS_STREAMME;
// return VIS_INVISIBLE;
}
// We might be fading
a = mi->GetAtomicFromDistance( dist /*- FADE_DISTANCE*/ );
mi->mIsDamaged = false;
if ( a == nullptr )
model_info.mIsDamaged = false;
if ( model_info.GetAtomicFromDistance( dist /*- FADE_DISTANCE*/ ) ==
nullptr )
{
// request model
// if ( dist - FADE_DISTANCE - STREAM_DISTANCE <
// mi->GetLargestLodDistance() &&
// request )
return VIS_STREAMME;
// return VIS_INVISIBLE;
}
if ( ent->mRwObject == nullptr )
ent->CreateRwObject();
assert( ent->mRwObject );
// RpAtomic *rwobj = (RpAtomic *)ent->mRwObject;
/*if ( RpAtomicGetGeometry( a ) != RpAtomicGetGeometry( rwobj ) )
RpAtomicSetGeometry(
rwobj, RpAtomicGetGeometry( a ),
rpATOMICSAMEBOUNDINGSPHERE ); */
mi->IncreaseAlpha();
if ( ent->mRwObject == nullptr || !ent->bIsVisible )
if ( entity.mRwObject == nullptr )
entity.CreateRwObject();
assert( entity.mRwObject );
model_info.IncreaseAlpha();
if ( entity.mRwObject == nullptr || !entity.bIsVisible )
return VIS_INVISIBLE;
return VIS_OFFSCREEN;
}
int32_t Renderer::SetupEntityVisibility( Entity *ent )
{
auto *base_mi = ModelInfo::GetModelInfo( ent->mModelIndex );
/*
if ( !ent->GetIsOnScreen() )
switch ( base_mi->mType )
{
case MITYPE_WEAPON:
case MITYPE_SIMPLE:
{
if ( ent->bDontStream )
{
if ( ent->mRwObject != nullptr && ent->bIsVisible )
return VIS_VISIBLE;
else
return VIS_INVISIBLE;
}
return SetupSimpleModelVisibility(
*ent, *static_cast<SimpleModelInfo *>( base_mi ) );
}
case MITYPE_TIME:
{
TimeModelInfo *ti;
ti = static_cast<TimeModelInfo *>( base_mi );
auto other = ti->mOtherTimeModel;
if ( Clock::GetIsTimeInRange( ti->mTimeOn, ti->mTimeOff ) )
{
// don't fade in, or between time objects
ti->mAlpha = 255;
return SetupSimpleModelVisibility(
*ent, *static_cast<SimpleModelInfo *>( base_mi ) );
}
else
{
mi->m_alpha = 255;
return VIS_OFFSCREEN;
// Hide if possible
return VIS_INVISIBLE;
}
}
default:
if ( ent->mRwObject == nullptr )
return VIS_STREAMME;
return ent->bIsVisible ? VIS_VISIBLE : VIS_INVISIBLE;
}
}
int32_t
Renderer::SetupBigBuildingSimpleVisibility( Entity & entity,
SimpleModelInfo &model_info )
{
if ( !entity.bIsVisible )
return VIS_INVISIBLE;
auto dist = length( entity.mMatrix.m_matrix.pos - mCameraPosition );
SimpleModelInfo *nonLOD = model_info.GetRelatedModel();
// Find out whether to draw below near distance.
// This is only the case if there is a non-LOD which is either not
// loaded or not completely faded in yet.
if ( dist < model_info.GetNearDistance() &&
dist < 300.0f * /*GameRendererConfigBlock::It.LodMultiplier*/ 4.0f )
{
// No non-LOD or non-LOD is completely visible.
if ( nonLOD == nullptr ||
( nonLOD->mAtomics[0] && nonLOD->mAlpha == 255 ) )
return VIS_INVISIBLE;
}
if ( RpAtomic *a = model_info.GetFirstAtomicFromDistance( dist ); a )
{
if ( entity.mRwObject == nullptr )
entity.CreateRwObject();
assert( entity.mRwObject );
return VIS_VISIBLE;
}
return VIS_INVISIBLE;
}
int32_t Renderer::SetupBigBuildingVisibility( Entity *ent )
{
auto *base_mi = ModelInfo::GetModelInfo( ent->mModelIndex );
switch ( base_mi->mType )
{
case MITYPE_TIME:
{
// TODO: account for timed objects
// Hide if possible
TimeModelInfo *ti;
ti = static_cast<TimeModelInfo *>( base_mi );
if ( !Clock::GetIsTimeInRange( ti->mTimeOn, ti->mTimeOff ) )
return VIS_INVISIBLE;
else
{
CVisibilityPlugins::InsertEntityIntoSortedList( ent, dist );
ent->bDistanceFade = true;
return VIS_OFFSCREEN; // Why this?
}*/
// don't fade in, or between time objects
ti->mAlpha = 255;
return SetupBigBuildingSimpleVisibility(
*ent, *static_cast<SimpleModelInfo *>( base_mi ) );
}
}
case MITYPE_VEHICLE:
if ( ent->mRwObject == nullptr )
return VIS_STREAMME;
return ent->bIsVisible ? VIS_VISIBLE : VIS_INVISIBLE;
default:
case MITYPE_SIMPLE:
{
if ( ent->mArea != Game::CurrentArea && ent->mArea != 13 )
return VIS_INVISIBLE;
return SetupBigBuildingSimpleVisibility(
*ent, *static_cast<SimpleModelInfo *>( base_mi ) );
}
}
}
void Renderer::PreRender()
......@@ -394,38 +378,6 @@ void Renderer::Render()
InMemoryFuncCall<void>( 0x57BF40 );
}
int32_t Renderer::SetupBigBuildingVisibility( Entity *ent )
{
auto *base_mi = ModelInfo::GetModelInfo( ent->mModelIndex );
if ( base_mi->mType != MITYPE_SIMPLE )
return ent->bIsVisible ? VIS_VISIBLE : VIS_INVISIBLE;
auto *mi = static_cast<SimpleModelInfo *>( base_mi );
auto dist = length( ent->mMatrix.m_matrix.pos - mCameraPosition );
SimpleModelInfo *nonLOD = mi->GetRelatedModel();
// Find out whether to draw below near distance.
// This is only the case if there is a non-LOD which is either not
// loaded or not completely faded in yet.
if ( dist < mi->GetNearDistance() &&
dist < 300.0f * /*GameRendererConfigBlock::It.LodMultiplier*/ 4.0f )
{
// No non-LOD or non-LOD is completely visible.
if ( nonLOD == nullptr || nonLOD->mAtomics[0] && nonLOD->mAlpha == 255 )
return VIS_INVISIBLE;
}
RpAtomic *a = mi->GetAtomicFromDistance( dist );
if ( a )
{
if ( ent->mRwObject == nullptr )
ent->CreateRwObject();
assert( ent->mRwObject );
// RpAtomic *rwobj = (RpAtomic *)ent->mRwObject;
if ( !ent->bIsVisible )
return VIS_INVISIBLE;
return VIS_VISIBLE;
}
return VIS_INVISIBLE;
}
void Renderer::Patch()
{
RedirectJump( 0x4C85E0, reinterpret_cast<void *>( Renderer::ScanWorld ) );
......
......@@ -7,14 +7,21 @@
#include <ConfigUtils/ConfigBlock.h>
#include <array>
class SimpleModelInfo;
class Renderer
{
public:
static void ScanWorld();
static void PreRender();
static void Render();
static void ScanSectorList( const WorldSector &sector );
static int32_t SetupEntityVisibility( Entity *ent );
static void ScanWorld();
static void PreRender();
static void Render();
static void ScanSectorList( const WorldSector &sector );
static int32_t SetupEntityVisibility( Entity *ent );
static int32_t SetupSimpleModelVisibility( Entity & entity,
SimpleModelInfo &model_info );
static int32_t
SetupBigBuildingSimpleVisibility( Entity & entity,
SimpleModelInfo &model_info );
static int32_t SetupBigBuildingVisibility( Entity *ent );
static uint32_t mLightCount;
......
//
// Created by peter on 29.11.2020.
//
#include "Shadows.h"
#include <injection_utils/InjectorHelpers.h>
void Shadows::Patch()
{
// Buggy cutscene shadows
RedirectJump( 0x625D80,
reinterpret_cast<void *>( IsCutsceneShadowEnabled ) );
RedirectJump( 0x56DC70, reinterpret_cast<void *>(
Shadows::StoreShadowForPedObject ) );
RedirectJump( 0x56D410,
reinterpret_cast<void *>( Shadows::StoreShadowForPole ) );
RedirectJump( 0x56DCD0,
reinterpret_cast<void *>( Shadows::StoreCarLightShadow ) );
RedirectJump( 0x56E780,
reinterpret_cast<void *>( Shadows::StoreStaticShadow ) );
RedirectJump( 0x56DFA0,
reinterpret_cast<void *>( Shadows::StoreShadowForCar ) );
}
void Shadows::StoreShadowForCar( Entity * ) {}
void Shadows::StoreShadowForPedObject( Entity *, float, float, float, float,
float, float )
{
}
void Shadows::StoreShadowForPole( Entity *, float, float, float, float, float,
uint32_t )
{
}
void Shadows::StoreCarLightShadow( Entity *, int32_t, RwTexture *, Vector *,
float, float, float, float, uint8_t, uint8_t,
uint8_t, float )
{
}
void Shadows::StoreStaticShadow( uint32_t, uint8_t, RwTexture *, Vector *,
float, float, float, float, int16_t, uint8_t,
uint8_t, uint8_t, float, float, float, bool,
float )
{
}
bool Shadows::IsCutsceneShadowEnabled() { return false; }
//
// Created by peter on 29.11.2020.
//
#pragma once
#include <common_headers.h>
class Entity;
class Vector;
/// Original game static shadows functions, we remove them in favor of new
/// lighting system TODO: Allow to use draw blob shadows, via config
class Shadows
{
public:
static void StoreShadowForPedObject( Entity *, float, float, float, float,
float, float );
static void StoreShadowForPole( Entity *, float, float, float, float, float,
uint32_t );
static void StoreCarLightShadow( Entity *, int32_t, RwTexture *, Vector *,
float, float, float, float, uint8_t,
uint8_t, uint8_t, float );
static void StoreStaticShadow( uint32_t, uint8_t, RwTexture *, Vector *,
float, float, float, float, int16_t, uint8_t,
uint8_t, uint8_t, float, float, float, bool,
float );
static void StoreShadowForCar( Entity * );
static bool IsCutsceneShadowEnabled();
static void Patch();
};
\ No newline at end of file
......@@ -93,7 +93,7 @@ class RTAOPass
struct AOParams
{
float min_distance = 0.001f;
float max_distance = 10.0f;
float max_distance = 1.5f;
float max_draw_dist = 1000.0f;
uint32_t time_stamp = 0;
} mParams;
......
......@@ -48,10 +48,36 @@ void main()
{
accum = pass_args.accumulation;
// high velocity reduce sample count, to avoid overblurring of moving objects
tspp = min(tspp + 1, uint(float(max_tspp) * max(1 - velocity, 0)) + 1);
tspp = min(tspp + 1, uint(float(max_tspp) * max(1 - velocity/2, 0)) + 1);
float max_value = min(_moments.x + _moments.y, 1.0f);
float min_value = max(_moments.x - _moments.y, 0.0f);
if(min_tspp_for_temp_var <= min_tspp_for_temp_var)
{
vec2 spatial_moments = moments;
float spatial_weight = 1;
// compute spatial variance
for(int x =-2; x <=2; x++)
for(int y =-2; y <=2; y++)
{
if(x == 0 && y == 0)
continue;
vec4 value_s = imageLoad(tx_new_frame, pos + ivec2(x,y));
float current_luma_s = dot(value.xyz,g_luma);
float sq_mean_luma_s = current_luma*current_luma;
spatial_moments += vec2(current_luma_s, sq_mean_luma_s);
spatial_weight += 1;
}
spatial_moments /= spatial_weight;
float spatial_variance = spatial_moments.y - spatial_moments.x*spatial_moments.x;
max_value = min(spatial_moments.x + spatial_variance, 1.0f);
min_value = max(spatial_moments.x - spatial_variance, 0.0f);
}
if(current_luma > max_value || current_luma < min_value)
tspp = 1;
float inv_tspp = 1.0f/float(tspp);
result_moments = (_moments * (float(tspp) - 1) + moments) / float(tspp);
......
......@@ -108,7 +108,7 @@ void main()
const float depth_eps = FloatPrecision(depth, 10);
// TODO: Allow threshold adjustment
bool reject_sample = abs(depth - dot(_depth, _weights)) > 0.5 || dot(normals_diff, _weights) > 0.1f;
bool reject_sample = abs(depth - dot(_depth, _weights)) > 2.0 || dot(normals_diff, _weights) > 0.1f;
uint _tspp = imageLoad(tx_old_tspp_cache, _pos).r;
......